Skip to content
Snippets Groups Projects
wrap_cl.hpp 124 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef _AFJHAYYTA_PYOPENCL_HEADER_SEEN_WRAP_CL_HPP
    #define _AFJHAYYTA_PYOPENCL_HEADER_SEEN_WRAP_CL_HPP
    
    // CL 1.2 undecided:
    // clSetPrintfCallback
    
    // {{{ includes
    
    #define CL_USE_DEPRECATED_OPENCL_1_1_APIS
    // #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
    
    #ifdef __APPLE__
    
    // Mac ------------------------------------------------------------------------
    #include <OpenCL/opencl.h>
    #ifdef HAVE_GL
    
    #define PYOPENCL_GL_SHARING_VERSION 1
    
    #include <OpenGL/OpenGL.h>
    #include <OpenCL/cl_gl.h>
    #include <OpenCL/cl_gl_ext.h>
    #endif
    
    #else
    
    // elsewhere ------------------------------------------------------------------
    
    #define CL_TARGET_OPENCL_VERSION 220
    
    
    #include <CL/cl.h>
    
    #include "pyopencl_ext.h"
    
    
    #if defined(_WIN32)
    #define NOMINMAX
    #include <windows.h>
    #endif
    
    #ifdef HAVE_GL
    #include <GL/gl.h>
    #include <CL/cl_gl.h>
    #endif
    
    #if defined(cl_khr_gl_sharing) && (cl_khr_gl_sharing >= 1)
    #define PYOPENCL_GL_SHARING_VERSION cl_khr_gl_sharing
    #endif
    
    #endif
    
    
    #include <thread>
    #include <mutex>
    #include <condition_variable>
    
    
    #include <stdexcept>
    #include <iostream>
    #include <vector>
    #include <utility>
    #include <numeric>
    #include "wrap_helpers.hpp"
    #include "numpy_init.hpp"
    #include "tools.hpp"
    
    #ifdef PYOPENCL_PRETEND_CL_VERSION
    #define PYOPENCL_CL_VERSION PYOPENCL_PRETEND_CL_VERSION
    #else
    
    
    #if defined(CL_VERSION_2_2)
    #define PYOPENCL_CL_VERSION 0x2020
    #elif defined(CL_VERSION_2_1)
    #define PYOPENCL_CL_VERSION 0x2010
    #elif defined(CL_VERSION_2_0)
    #define PYOPENCL_CL_VERSION 0x2000
    #elif defined(CL_VERSION_1_2)
    
    #define PYOPENCL_CL_VERSION 0x1020
    #elif defined(CL_VERSION_1_1)
    #define PYOPENCL_CL_VERSION 0x1010
    #else
    #define PYOPENCL_CL_VERSION 0x1000
    #endif
    
    #endif
    
    
    #if PY_VERSION_HEX >= 0x03000000
    #define PYOPENCL_USE_NEW_BUFFER_INTERFACE
    
    #define PYOPENCL_STD_MOVE_IF_NEW_BUF_INTF(s) std::move(s)
    #else
    #define PYOPENCL_STD_MOVE_IF_NEW_BUF_INTF(s) (s)
    
    // }}}
    
    
    
    
    
    // {{{ tools
    #if PY_VERSION_HEX >= 0x02050000
      typedef Py_ssize_t PYOPENCL_BUFFER_SIZE_T;
    #else
      typedef int PYOPENCL_BUFFER_SIZE_T;
    #endif
    
    #define PYOPENCL_CAST_BOOL(B) ((B) ? CL_TRUE : CL_FALSE)
    
    
    
    
    
    #define PYOPENCL_DEPRECATED(WHAT, KILL_VERSION, EXTRA_MSG) \
      { \
        PyErr_Warn( \
            PyExc_DeprecationWarning, \
            WHAT " is deprecated and will stop working in PyOpenCL " KILL_VERSION". " \
            EXTRA_MSG); \
      }
    
    #if PYOPENCL_CL_VERSION >= 0x1020
    
    #define PYOPENCL_GET_EXT_FUN(PLATFORM, NAME, VAR) \
        NAME##_fn VAR \
          = (NAME##_fn) \
          clGetExtensionFunctionAddressForPlatform(PLATFORM, #NAME); \
        \
        if (!VAR) \
          throw error(#NAME, CL_INVALID_VALUE, #NAME \
              "not available");
    
    #else
    
    #define PYOPENCL_GET_EXT_FUN(PLATFORM, NAME, VAR) \
        NAME##_fn VAR \
          = (NAME##_fn) \
          clGetExtensionFunctionAddress(#NAME); \
        \
        if (!VAR) \
          throw error(#NAME, CL_INVALID_VALUE, #NAME \
              "not available");
    
    #endif
    
    
    #define PYOPENCL_PARSE_PY_DEVICES \
        std::vector<cl_device_id> devices_vec; \
        cl_uint num_devices; \
        cl_device_id *devices; \
        \
        if (py_devices.ptr() == Py_None) \
        { \
          num_devices = 0; \
          devices = 0; \
        } \
        else \
        { \
    
          for (py::handle py_dev: py_devices) \
    
            devices_vec.push_back( \
    
                (py_dev).cast<device &>().data()); \
    
          num_devices = devices_vec.size(); \
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          devices = devices_vec.empty( ) ? nullptr : &devices_vec.front(); \
    
        } \
    
    
    #define PYOPENCL_RETRY_RETURN_IF_MEM_ERROR(OPERATION) \
        try \
        { \
          OPERATION \
        } \
        catch (pyopencl::error &e) \
        { \
          if (!e.is_out_of_memory()) \
            throw; \
        } \
        \
        /* If we get here, we got an error from CL.
         * We should run the Python GC to try and free up
         * some memory references. */ \
        run_python_gc(); \
        \
        /* Now retry the allocation. If it fails again,
         * let it fail. */ \
        { \
          OPERATION \
        }
    
    
    
    
    #define PYOPENCL_RETRY_IF_MEM_ERROR(OPERATION) \
      { \
        bool failed_with_mem_error = false; \
        try \
        { \
          OPERATION \
        } \
        catch (pyopencl::error &e) \
        { \
          failed_with_mem_error = true; \
          if (!e.is_out_of_memory()) \
            throw; \
        } \
        \
        if (failed_with_mem_error) \
        { \
          /* If we get here, we got an error from CL.
           * We should run the Python GC to try and free up
           * some memory references. */ \
          run_python_gc(); \
          \
          /* Now retry the allocation. If it fails again,
           * let it fail. */ \
          { \
            OPERATION \
          } \
        } \
      }
    
    // }}}
    
    // {{{ tracing and error reporting
    #ifdef PYOPENCL_TRACE
      #define PYOPENCL_PRINT_CALL_TRACE(NAME) \
        std::cerr << NAME << std::endl;
      #define PYOPENCL_PRINT_CALL_TRACE_INFO(NAME, EXTRA_INFO) \
        std::cerr << NAME << " (" << EXTRA_INFO << ')' << std::endl;
    #else
      #define PYOPENCL_PRINT_CALL_TRACE(NAME) /*nothing*/
      #define PYOPENCL_PRINT_CALL_TRACE_INFO(NAME, EXTRA_INFO) /*nothing*/
    #endif
    
    #define PYOPENCL_CALL_GUARDED_THREADED_WITH_TRACE_INFO(NAME, ARGLIST, TRACE_INFO) \
      { \
        PYOPENCL_PRINT_CALL_TRACE_INFO(#NAME, TRACE_INFO); \
        cl_int status_code; \
    
        { \
          py::gil_scoped_release release; \
    
          status_code = NAME ARGLIST; \
    
        if (status_code != CL_SUCCESS) \
          throw pyopencl::error(#NAME, status_code);\
      }
    
    #define PYOPENCL_CALL_GUARDED_WITH_TRACE_INFO(NAME, ARGLIST, TRACE_INFO) \
      { \
        PYOPENCL_PRINT_CALL_TRACE_INFO(#NAME, TRACE_INFO); \
        cl_int status_code; \
        status_code = NAME ARGLIST; \
        if (status_code != CL_SUCCESS) \
          throw pyopencl::error(#NAME, status_code);\
      }
    
    #define PYOPENCL_CALL_GUARDED_THREADED(NAME, ARGLIST) \
      { \
        PYOPENCL_PRINT_CALL_TRACE(#NAME); \
        cl_int status_code; \
    
        { \
          py::gil_scoped_release release; \
    
          status_code = NAME ARGLIST; \
    
        if (status_code != CL_SUCCESS) \
          throw pyopencl::error(#NAME, status_code);\
      }
    
    #define PYOPENCL_CALL_GUARDED(NAME, ARGLIST) \
      { \
        PYOPENCL_PRINT_CALL_TRACE(#NAME); \
        cl_int status_code; \
        status_code = NAME ARGLIST; \
        if (status_code != CL_SUCCESS) \
          throw pyopencl::error(#NAME, status_code);\
      }
    #define PYOPENCL_CALL_GUARDED_CLEANUP(NAME, ARGLIST) \
      { \
        PYOPENCL_PRINT_CALL_TRACE(#NAME); \
        cl_int status_code; \
        status_code = NAME ARGLIST; \
        if (status_code != CL_SUCCESS) \
          std::cerr \
            << "PyOpenCL WARNING: a clean-up operation failed (dead context maybe?)" \
            << std::endl \
            << #NAME " failed with code " << status_code \
            << std::endl; \
      }
    
    // }}}
    
    // {{{ get_info helpers
    #define PYOPENCL_GET_OPAQUE_INFO(WHAT, FIRST_ARG, SECOND_ARG, CL_TYPE, TYPE) \
      { \
        CL_TYPE param_value; \
        PYOPENCL_CALL_GUARDED(clGet##WHAT##Info, \
              (FIRST_ARG, SECOND_ARG, sizeof(param_value), &param_value, 0)); \
        if (param_value) \
          return py::object(handle_from_new_ptr( \
                new TYPE(param_value, /*retain*/ true))); \
        else \
    
          return py::none(); \
    
      }
    
    #define PYOPENCL_GET_VEC_INFO(WHAT, FIRST_ARG, SECOND_ARG, RES_VEC) \
      { \
        size_t size; \
        PYOPENCL_CALL_GUARDED(clGet##WHAT##Info, \
            (FIRST_ARG, SECOND_ARG, 0, 0, &size)); \
        \
        RES_VEC.resize(size / sizeof(RES_VEC.front())); \
        \
        PYOPENCL_CALL_GUARDED(clGet##WHAT##Info, \
            (FIRST_ARG, SECOND_ARG, size, \
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
             RES_VEC.empty( ) ? nullptr : &RES_VEC.front(), &size)); \
    
      }
    
    #define PYOPENCL_GET_STR_INFO(WHAT, FIRST_ARG, SECOND_ARG) \
      { \
        size_t param_value_size; \
        PYOPENCL_CALL_GUARDED(clGet##WHAT##Info, \
            (FIRST_ARG, SECOND_ARG, 0, 0, &param_value_size)); \
        \
        std::vector<char> param_value(param_value_size); \
        PYOPENCL_CALL_GUARDED(clGet##WHAT##Info, \
            (FIRST_ARG, SECOND_ARG, param_value_size,  \
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
             param_value.empty( ) ? nullptr : &param_value.front(), &param_value_size)); \
    
        return py::cast( \
    
            param_value.empty( ) ? "" : std::string(&param_value.front(), param_value_size-1)); \
      }
    
    
    
    
    #define PYOPENCL_GET_INTEGRAL_INFO(WHAT, FIRST_ARG, SECOND_ARG, TYPE) \
      { \
        TYPE param_value; \
        PYOPENCL_CALL_GUARDED(clGet##WHAT##Info, \
            (FIRST_ARG, SECOND_ARG, sizeof(param_value), &param_value, 0)); \
    
        return py::cast(param_value); \
    
      }
    
    // }}}
    
    // {{{ event helpers --------------------------------------------------------------
    #define PYOPENCL_PARSE_WAIT_FOR \
        cl_uint num_events_in_wait_list = 0; \
        std::vector<cl_event> event_wait_list; \
        \
        if (py_wait_for.ptr() != Py_None) \
        { \
          event_wait_list.resize(len(py_wait_for)); \
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          for (py::handle evt: py_wait_for) \
    
            event_wait_list[num_events_in_wait_list++] = \
    
              evt.cast<const event &>().data(); \
    
        }
    
    #define PYOPENCL_WAITLIST_ARGS \
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
        num_events_in_wait_list, event_wait_list.empty( ) ? nullptr : &event_wait_list.front()
    
    
    #define PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, obj) \
        try \
        { \
          return new nanny_event(evt, false, obj); \
        } \
        catch (...) \
        { \
          clReleaseEvent(evt); \
          throw; \
        }
    
    #define PYOPENCL_RETURN_NEW_EVENT(evt) \
        try \
        { \
          return new event(evt, false); \
        } \
        catch (...) \
        { \
          clReleaseEvent(evt); \
          throw; \
        }
    
    // }}}
    
    // {{{ equality testing
    #define PYOPENCL_EQUALITY_TESTS(cls) \
        bool operator==(cls const &other) const \
        { return data() == other.data(); } \
        bool operator!=(cls const &other) const \
        { return data() != other.data(); } \
        long hash() const \
        { return (long) (intptr_t) data(); }
    // }}}
    
    
    
    namespace pyopencl
    {
      // {{{ error
      class error : public std::runtime_error
      {
        private:
          const char *m_routine;
          cl_int m_code;
    
        public:
          error(const char *rout, cl_int c, const char *msg="")
            : std::runtime_error(msg), m_routine(rout), m_code(c)
          { }
    
          const char *routine() const
          {
            return m_routine;
          }
    
          cl_int code() const
          {
            return m_code;
          }
    
          bool is_out_of_memory() const
          {
            return (code() == CL_MEM_OBJECT_ALLOCATION_FAILURE
                || code() == CL_OUT_OF_RESOURCES
                || code() == CL_OUT_OF_HOST_MEMORY);
          }
    
      };
    
      // }}}
    
    
      // {{{ buffer interface helper
      //
    #ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE
    
      class py_buffer_wrapper : public noncopyable
    
      {
        private:
          bool m_initialized;
    
        public:
          Py_buffer m_buf;
    
        py_buffer_wrapper()
          : m_initialized(false)
        {}
    
        void get(PyObject *obj, int flags)
        {
          if (PyObject_GetBuffer(obj, &m_buf, flags))
            throw py::error_already_set();
    
          m_initialized = true;
        }
    
        virtual ~py_buffer_wrapper()
        {
          if (m_initialized)
            PyBuffer_Release(&m_buf);
        }
      };
    #endif
    
      // }}}
    
      inline
      py::tuple get_cl_header_version()
      {
        return py::make_tuple(
            PYOPENCL_CL_VERSION >> (3*4),
            (PYOPENCL_CL_VERSION >> (1*4)) & 0xff
            );
      }
    
    
      // {{{ platform
    
    
      class platform : noncopyable
    
      {
        private:
          cl_platform_id m_platform;
    
        public:
          platform(cl_platform_id pid)
          : m_platform(pid)
          { }
    
          platform(cl_platform_id pid, bool /*retain (ignored)*/)
          : m_platform(pid)
          { }
    
          cl_platform_id data() const
          {
            return m_platform;
          }
    
          PYOPENCL_EQUALITY_TESTS(platform);
    
          py::object get_info(cl_platform_info param_name) const
          {
            switch (param_name)
            {
              case CL_PLATFORM_PROFILE:
              case CL_PLATFORM_VERSION:
              case CL_PLATFORM_NAME:
              case CL_PLATFORM_VENDOR:
    #if !(defined(CL_PLATFORM_NVIDIA) && CL_PLATFORM_NVIDIA == 0x3001)
              case CL_PLATFORM_EXTENSIONS:
    #endif
                PYOPENCL_GET_STR_INFO(Platform, m_platform, param_name);
    
              default:
                throw error("Platform.get_info", CL_INVALID_VALUE);
            }
          }
    
          py::list get_devices(cl_device_type devtype);
      };
    
    
    
    
      inline
      py::list get_platforms()
      {
        cl_uint num_platforms = 0;
        PYOPENCL_CALL_GUARDED(clGetPlatformIDs, (0, 0, &num_platforms));
    
        std::vector<cl_platform_id> platforms(num_platforms);
        PYOPENCL_CALL_GUARDED(clGetPlatformIDs,
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
            (num_platforms, platforms.empty( ) ? nullptr : &platforms.front(), &num_platforms));
    
    
        py::list result;
    
        for (cl_platform_id pid: platforms)
    
          result.append(handle_from_new_ptr(
                new platform(pid)));
    
        return result;
      }
    
      // }}}
    
    
      // {{{ device
    
    
      class device : noncopyable
    
      {
        public:
          enum reference_type_t {
            REF_NOT_OWNABLE,
    #if PYOPENCL_CL_VERSION >= 0x1020
            REF_CL_1_2,
    #endif
          };
        private:
          cl_device_id m_device;
          reference_type_t m_ref_type;
    
        public:
          device(cl_device_id did)
          : m_device(did), m_ref_type(REF_NOT_OWNABLE)
          { }
    
          device(cl_device_id did, bool retain, reference_type_t ref_type=REF_NOT_OWNABLE)
          : m_device(did), m_ref_type(ref_type)
          {
            if (retain && ref_type != REF_NOT_OWNABLE)
            {
              if (false)
              { }
    
    #if PYOPENCL_CL_VERSION >= 0x1020
              else if (ref_type == REF_CL_1_2)
              {
                PYOPENCL_CALL_GUARDED(clRetainDevice, (did));
              }
    #endif
    
              else
                throw error("Device", CL_INVALID_VALUE,
                    "cannot own references to devices when device fission or CL 1.2 is not available");
            }
          }
    
          ~device()
          {
    #if PYOPENCL_CL_VERSION >= 0x1020
    
              PYOPENCL_CALL_GUARDED_CLEANUP(clReleaseDevice, (m_device));
    
    #endif
          }
    
          cl_device_id data() const
          {
            return m_device;
          }
    
          PYOPENCL_EQUALITY_TESTS(device);
    
          py::object get_info(cl_device_info param_name) const
          {
    #define DEV_GET_INT_INF(TYPE) \
            PYOPENCL_GET_INTEGRAL_INFO(Device, m_device, param_name, TYPE);
    
            switch (param_name)
            {
              case CL_DEVICE_TYPE: DEV_GET_INT_INF(cl_device_type);
              case CL_DEVICE_VENDOR_ID: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_COMPUTE_UNITS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_WORK_GROUP_SIZE: DEV_GET_INT_INF(size_t);
    
              case CL_DEVICE_MAX_WORK_ITEM_SIZES:
                {
                  std::vector<size_t> result;
                  PYOPENCL_GET_VEC_INFO(Device, m_device, param_name, result);
                  PYOPENCL_RETURN_VECTOR(size_t, result);
                }
    
              case CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE: DEV_GET_INT_INF(cl_uint);
    
              case CL_DEVICE_MAX_CLOCK_FREQUENCY: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_ADDRESS_BITS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_READ_IMAGE_ARGS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_WRITE_IMAGE_ARGS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_MEM_ALLOC_SIZE: DEV_GET_INT_INF(cl_ulong);
              case CL_DEVICE_IMAGE2D_MAX_WIDTH: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_IMAGE2D_MAX_HEIGHT: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_IMAGE3D_MAX_WIDTH: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_IMAGE3D_MAX_HEIGHT: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_IMAGE3D_MAX_DEPTH: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_IMAGE_SUPPORT: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_MAX_PARAMETER_SIZE: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_MAX_SAMPLERS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MEM_BASE_ADDR_ALIGN: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_SINGLE_FP_CONFIG: DEV_GET_INT_INF(cl_device_fp_config);
    #ifdef CL_DEVICE_DOUBLE_FP_CONFIG
              case CL_DEVICE_DOUBLE_FP_CONFIG: DEV_GET_INT_INF(cl_device_fp_config);
    #endif
    #ifdef CL_DEVICE_HALF_FP_CONFIG
              case CL_DEVICE_HALF_FP_CONFIG: DEV_GET_INT_INF(cl_device_fp_config);
    #endif
    
              case CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: DEV_GET_INT_INF(cl_device_mem_cache_type);
              case CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_GLOBAL_MEM_CACHE_SIZE: DEV_GET_INT_INF(cl_ulong);
              case CL_DEVICE_GLOBAL_MEM_SIZE: DEV_GET_INT_INF(cl_ulong);
    
              case CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: DEV_GET_INT_INF(cl_ulong);
              case CL_DEVICE_MAX_CONSTANT_ARGS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_LOCAL_MEM_TYPE: DEV_GET_INT_INF(cl_device_local_mem_type);
              case CL_DEVICE_LOCAL_MEM_SIZE: DEV_GET_INT_INF(cl_ulong);
              case CL_DEVICE_ERROR_CORRECTION_SUPPORT: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_PROFILING_TIMER_RESOLUTION: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_ENDIAN_LITTLE: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_AVAILABLE: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_COMPILER_AVAILABLE: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_EXECUTION_CAPABILITIES: DEV_GET_INT_INF(cl_device_exec_capabilities);
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
    #if PYOPENCL_CL_VERSION >= 0x2000
              case CL_DEVICE_QUEUE_ON_HOST_PROPERTIES: DEV_GET_INT_INF(cl_command_queue_properties);
    #else
    
              case CL_DEVICE_QUEUE_PROPERTIES: DEV_GET_INT_INF(cl_command_queue_properties);
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
    #endif
    
    
              case CL_DEVICE_NAME:
              case CL_DEVICE_VENDOR:
              case CL_DRIVER_VERSION:
              case CL_DEVICE_PROFILE:
              case CL_DEVICE_VERSION:
              case CL_DEVICE_EXTENSIONS:
                PYOPENCL_GET_STR_INFO(Device, m_device, param_name);
    
              case CL_DEVICE_PLATFORM:
                PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_platform_id, platform);
    
    #if PYOPENCL_CL_VERSION >= 0x1010
              case CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF: DEV_GET_INT_INF(cl_uint);
    
              case CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_NATIVE_VECTOR_WIDTH_INT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF: DEV_GET_INT_INF(cl_uint);
    
              case CL_DEVICE_HOST_UNIFIED_MEMORY: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_OPENCL_C_VERSION:
                PYOPENCL_GET_STR_INFO(Device, m_device, param_name);
    #endif
    #ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV
              case CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV:
              case CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV:
              case CL_DEVICE_REGISTERS_PER_BLOCK_NV:
              case CL_DEVICE_WARP_SIZE_NV:
                DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_GPU_OVERLAP_NV:
              case CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV:
              case CL_DEVICE_INTEGRATED_MEMORY_NV:
                DEV_GET_INT_INF(cl_bool);
    #endif
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
    #ifdef CL_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT_NV
              case CL_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT_NV:
                DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_PCI_BUS_ID_NV
              case CL_DEVICE_PCI_BUS_ID_NV:
                DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_PCI_SLOT_ID_NV
              case CL_DEVICE_PCI_SLOT_ID_NV:
                DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_THREAD_TRACE_SUPPORTED_AMD
              case CL_DEVICE_THREAD_TRACE_SUPPORTED_AMD: DEV_GET_INT_INF(cl_bool);
    #endif
    #ifdef CL_DEVICE_GFXIP_MAJOR_AMD
              case CL_DEVICE_GFXIP_MAJOR_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_GFXIP_MINOR_AMD
              case CL_DEVICE_GFXIP_MINOR_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_AVAILABLE_ASYNC_QUEUES_AMD
              case CL_DEVICE_AVAILABLE_ASYNC_QUEUES_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    
    #if PYOPENCL_CL_VERSION >= 0x1020
              case CL_DEVICE_LINKER_AVAILABLE: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_BUILT_IN_KERNELS:
                PYOPENCL_GET_STR_INFO(Device, m_device, param_name);
              case CL_DEVICE_IMAGE_MAX_BUFFER_SIZE: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_IMAGE_MAX_ARRAY_SIZE: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_PARENT_DEVICE:
                PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_device_id, device);
              case CL_DEVICE_PARTITION_MAX_SUB_DEVICES: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PARTITION_TYPE:
              case CL_DEVICE_PARTITION_PROPERTIES:
                {
                  std::vector<cl_device_partition_property> result;
                  PYOPENCL_GET_VEC_INFO(Device, m_device, param_name, result);
                  PYOPENCL_RETURN_VECTOR(cl_device_partition_property, result);
                }
              case CL_DEVICE_PARTITION_AFFINITY_DOMAIN:
                {
                  std::vector<cl_device_affinity_domain> result;
                  PYOPENCL_GET_VEC_INFO(Device, m_device, param_name, result);
                  PYOPENCL_RETURN_VECTOR(cl_device_affinity_domain, result);
                }
              case CL_DEVICE_REFERENCE_COUNT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_INTEROP_USER_SYNC: DEV_GET_INT_INF(cl_bool);
              case CL_DEVICE_PRINTF_BUFFER_SIZE: DEV_GET_INT_INF(cl_bool);
    #endif
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
    // {{{ AMD dev attrs cl_amd_device_attribute_query
    
    //
    // types of AMD dev attrs divined from
    // https://www.khronos.org/registry/cl/api/1.2/cl.hpp
    #ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD
              case CL_DEVICE_PROFILING_TIMER_OFFSET_AMD: DEV_GET_INT_INF(cl_ulong);
    #endif
    /* FIXME
    #ifdef CL_DEVICE_TOPOLOGY_AMD
              case CL_DEVICE_TOPOLOGY_AMD:
    #endif
    */
    #ifdef CL_DEVICE_BOARD_NAME_AMD
              case CL_DEVICE_BOARD_NAME_AMD: ;
                PYOPENCL_GET_STR_INFO(Device, m_device, param_name);
    #endif
    #ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD
              case CL_DEVICE_GLOBAL_FREE_MEMORY_AMD:
                {
                  std::vector<size_t> result;
                  PYOPENCL_GET_VEC_INFO(Device, m_device, param_name, result);
                  PYOPENCL_RETURN_VECTOR(size_t, result);
                }
    #endif
    #ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD
              case CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD
              case CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD
              case CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD
              case CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD
              case CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD
              case CL_DEVICE_LOCAL_MEM_BANKS_AMD: DEV_GET_INT_INF(cl_uint);
    #endif
    // }}}
    
    #ifdef CL_DEVICE_MAX_ATOMIC_COUNTERS_EXT
              case CL_DEVICE_MAX_ATOMIC_COUNTERS_EXT: DEV_GET_INT_INF(cl_uint);
    #endif
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
    #if PYOPENCL_CL_VERSION >= 0x2000
              case CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES: DEV_GET_INT_INF(cl_command_queue_properties);
              case CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_ON_DEVICE_QUEUES: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_MAX_ON_DEVICE_EVENTS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_SVM_CAPABILITIES: DEV_GET_INT_INF(cl_device_svm_capabilities);
              case CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE: DEV_GET_INT_INF(size_t);
              case CL_DEVICE_MAX_PIPE_ARGS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PIPE_MAX_PACKET_SIZE: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT: DEV_GET_INT_INF(cl_uint);
    #endif
    #if PYOPENCL_CL_VERSION >= 0x2010
    
              case CL_DEVICE_IL_VERSION:
                PYOPENCL_GET_STR_INFO(Device, m_device, param_name);
              case CL_DEVICE_MAX_NUM_SUB_GROUPS: DEV_GET_INT_INF(cl_uint);
              case CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS: DEV_GET_INT_INF(cl_bool);
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
    #endif
    #ifdef CL_DEVICE_ME_VERSION_INTEL
              case CL_DEVICE_ME_VERSION_INTEL: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM
              case CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_PAGE_SIZE_QCOM
              case CL_DEVICE_PAGE_SIZE_QCOM: DEV_GET_INT_INF(cl_uint);
    #endif
    #ifdef CL_DEVICE_SPIR_VERSIONS
              case CL_DEVICE_SPIR_VERSIONS:
                PYOPENCL_GET_STR_INFO(Device, m_device, param_name);
    #endif
    #ifdef CL_DEVICE_CORE_TEMPERATURE_ALTERA
              case CL_DEVICE_CORE_TEMPERATURE_ALTERA: DEV_GET_INT_INF(cl_int);
    #endif
    
    #ifdef CL_DEVICE_SIMULTANEOUS_INTEROPS_INTEL
              case CL_DEVICE_SIMULTANEOUS_INTEROPS_INTEL:
                {
                  std::vector<cl_uint> result;
                  PYOPENCL_GET_VEC_INFO(Device, m_device, param_name, result);
                  PYOPENCL_RETURN_VECTOR(cl_uint, result);
                }
    #endif
    #ifdef CL_DEVICE_NUM_SIMULTANEOUS_INTEROPS_INTEL
              case CL_DEVICE_NUM_SIMULTANEOUS_INTEROPS_INTEL: DEV_GET_INT_INF(cl_uint);
    #endif
    
    
              default:
                throw error("Device.get_info", CL_INVALID_VALUE);
            }
          }
    
    #if PYOPENCL_CL_VERSION >= 0x1020
          py::list create_sub_devices(py::object py_properties)
          {
            std::vector<cl_device_partition_property> properties;
    
            COPY_PY_LIST(cl_device_partition_property, properties);
            properties.push_back(0);
    
            cl_device_partition_property *props_ptr
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
              = properties.empty( ) ? nullptr : &properties.front();
    
    
            cl_uint num_entries;
            PYOPENCL_CALL_GUARDED(clCreateSubDevices,
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
                (m_device, props_ptr, 0, nullptr, &num_entries));
    
    
            std::vector<cl_device_id> result;
            result.resize(num_entries);
    
            PYOPENCL_CALL_GUARDED(clCreateSubDevices,
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
                (m_device, props_ptr, num_entries, &result.front(), nullptr));
    
    
            py::list py_result;
    
            for (cl_device_id did: result)
    
              py_result.append(handle_from_new_ptr(
                    new pyopencl::device(did, /*retain*/true,
                      device::REF_CL_1_2)));
            return py_result;
          }
    #endif
    
      };
    
    
    
    
      inline py::list platform::get_devices(cl_device_type devtype)
      {
        cl_uint num_devices = 0;
        PYOPENCL_PRINT_CALL_TRACE("clGetDeviceIDs");
        {
          cl_int status_code;
          status_code = clGetDeviceIDs(m_platform, devtype, 0, 0, &num_devices);
          if (status_code == CL_DEVICE_NOT_FOUND)
            num_devices = 0;
          else if (status_code != CL_SUCCESS) \
            throw pyopencl::error("clGetDeviceIDs", status_code);
        }
    
        if (num_devices == 0)
          return py::list();
    
        std::vector<cl_device_id> devices(num_devices);
        PYOPENCL_CALL_GUARDED(clGetDeviceIDs,
            (m_platform, devtype,
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
             num_devices, devices.empty( ) ? nullptr : &devices.front(), &num_devices));
    
    
        py::list result;
    
        for (cl_device_id did: devices)
    
          result.append(handle_from_new_ptr(
                new device(did)));
    
        return result;
      }
    
      // }}}
    
    
      // {{{ context
    
    
      class context : public noncopyable
    
      {
        private:
          cl_context m_context;
    
        public:
          context(cl_context ctx, bool retain)
            : m_context(ctx)
          {
            if (retain)
              PYOPENCL_CALL_GUARDED(clRetainContext, (ctx));
          }
    
          ~context()
          {
            PYOPENCL_CALL_GUARDED_CLEANUP(clReleaseContext,
                (m_context));
          }
    
          cl_context data() const
          {
            return m_context;
          }
    
          PYOPENCL_EQUALITY_TESTS(context);
    
          py::object get_info(cl_context_info param_name) const
          {
            switch (param_name)
            {
              case CL_CONTEXT_REFERENCE_COUNT:
                PYOPENCL_GET_INTEGRAL_INFO(
                    Context, m_context, param_name, cl_uint);
    
              case CL_CONTEXT_DEVICES:
                {
                  std::vector<cl_device_id> result;
                  PYOPENCL_GET_VEC_INFO(Context, m_context, param_name, result);
    
                  py::list py_result;
    
                  for (cl_device_id did: result)
    
                    py_result.append(handle_from_new_ptr(
                          new pyopencl::device(did)));
                  return py_result;
                }
    
              case CL_CONTEXT_PROPERTIES:
                {
                  std::vector<cl_context_properties> result;
                  PYOPENCL_GET_VEC_INFO(Context, m_context, param_name, result);
    
                  py::list py_result;
                  for (size_t i = 0; i < result.size(); i+=2)
                  {
                    cl_context_properties key = result[i];
                    py::object value;
                    switch (key)
                    {
                      case CL_CONTEXT_PLATFORM:
                        {
                          value = py::object(
                              handle_from_new_ptr(new platform(
                                reinterpret_cast<cl_platform_id>(result[i+1]))));
                          break;
                        }
    
    #if defined(PYOPENCL_GL_SHARING_VERSION) && (PYOPENCL_GL_SHARING_VERSION >= 1)
    #if defined(__APPLE__) && defined(HAVE_GL)
                      case CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE:
    #else
                      case CL_GL_CONTEXT_KHR:
                      case CL_EGL_DISPLAY_KHR:
                      case CL_GLX_DISPLAY_KHR:
                      case CL_WGL_HDC_KHR: