opencl_ruby_ffi 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,131 @@
1
+ module OpenCL
2
+
3
+ # Attaches a callback to memobj the will be called on memobj destruction
4
+ #
5
+ # ==== Attributes
6
+ #
7
+ # * +memobj+ - the Mem to attach the callback to
8
+ # * +options+ - a hash containing named options
9
+ # * +block+ - if provided, a callback invoked when memobj is released. Signature of the callback is { |Mem, FFI::Pointer to user_data| ... }
10
+ #
11
+ # ==== Options
12
+ #
13
+ # * +:user_data+ - a Pointer (or convertible to Pointer using to_ptr) to the memory area to pass to the callback
14
+ def self.set_mem_object_destructor_callback( memobj, options = {}, &proc )
15
+ @@callbacks.push( block ) if block
16
+ error = OpenCL.clSetMemObjectDestructorCallback( memobj, block, options[:user_data] )
17
+ OpenCL.error_check(error)
18
+ return self
19
+ end
20
+
21
+ # Maps the cl_mem object of OpenCL
22
+ class Mem
23
+
24
+ # Returns the Context associated to the Mem
25
+ def context
26
+ ptr = FFI::MemoryPointer.new( Context )
27
+ error = OpenCL.clGetMemObjectInfo(self, Mem::CONTEXT, Context.size, ptr, nil)
28
+ OpenCL.error_check(error)
29
+ return OpenCL::Context::new( ptr.read_pointer )
30
+ end
31
+
32
+ # Returns the Platform associated to the Mem
33
+ def platform
34
+ return self.context.platform
35
+ end
36
+
37
+ # Returns the Buffer this Buffer was created from using create_sub_buffer
38
+ def associated_memobject
39
+ ptr = FFI::MemoryPointer.new( Mem )
40
+ error = OpenCL.clGetMemObjectInfo(self, Mem::ASSOCIATED_MEMOBJECT, Mem.size, ptr, nil)
41
+ OpenCL.error_check(error)
42
+ return nil if ptr.read_pointer.null?
43
+ return OpenCL::Mem::new( ptr.read_pointer )
44
+ end
45
+
46
+ ##
47
+ # :method: offset()
48
+ # Returns the offset used to create this Buffer using create_sub_buffer
49
+
50
+ ##
51
+ # :method: size()
52
+ # Returns the size of the Buffer
53
+ %w( OFFSET SIZE ).each { |prop|
54
+ eval OpenCL.get_info("Mem", :size_t, prop)
55
+ }
56
+
57
+ ##
58
+ # :method: map_count()
59
+ # Returns the number of times this Mem is mapped
60
+
61
+ ##
62
+ # :method: reference_count()
63
+ # Returns the Mem reference counter
64
+ %w( MAP_COUNT REFERENCE_COUNT ).each { |prop|
65
+ eval OpenCL.get_info("Mem", :cl_uint, prop)
66
+ }
67
+
68
+ ##
69
+ # :method: type()
70
+ # Returns an OpenCL::Mem::Type corresponding to the Mem
71
+ eval OpenCL.get_info("Mem", :cl_mem_object_type, "TYPE")
72
+
73
+ ##
74
+ # :method: flags()
75
+ # Returns an OpenCL::Mem::Flags corresponding to the flags used at Mem creation
76
+ eval OpenCL.get_info("Mem", :cl_mem_flags, "FLAGS")
77
+
78
+ ##
79
+ # :method: host_ptr()
80
+ # Returns the host Pointer specified at Mem creation or the pointer + the ofsset if it is a sub-buffer. A null Pointer is returned otherwise.
81
+ eval OpenCL.get_info("Mem", :pointer, "HOST_PTR")
82
+
83
+ # Attaches a callback to memobj that will be called on the memobj destruction
84
+ #
85
+ # ==== Attributes
86
+ #
87
+ # * +options+ - a hash containing named options
88
+ # * +block+ - if provided, a callback invoked when memobj is released. Signature of the callback is { |Mem, FFI::Pointer to user_data| ... }
89
+ #
90
+ # ==== Options
91
+ #
92
+ # * +:user_data+ - a Pointer (or convertible to Pointer using to_ptr) to the memory area to pass to the callback
93
+ def set_destructor_callback( options = {}, &proc )
94
+ return OpenCL.set_mem_object_destructor_callback( self, options, &proc )
95
+ end
96
+
97
+ # Returns the texture_target argument specified in create_from_GL_texture for Mem
98
+ def GL_texture_target
99
+ param_value = MemoryPointer.new( :cl_GLenum )
100
+ error = OpenCL.clGetGLTextureInfo( self, OpenCL::GL_TEXTURE_TARGET, param_value.size, param_value, nil )
101
+ OpenCL.error_check(error)
102
+ return param_value.read_cl_GLenum
103
+ end
104
+
105
+ # Returns the miplevel argument specified in create_from_GL_texture for Mem
106
+ def GL_mimap_level
107
+ param_value = MemoryPointer.new( :cl_GLint )
108
+ error = OpenCL.clGetGLTextureInfo( self, OpenCL::GL_MIPMAP_LEVEL, param_value.size, param_value, nil )
109
+ OpenCL.error_check(error)
110
+ return param_value.read_cl_GLint
111
+ end
112
+
113
+ # Returns the type of the GL object associated with Mem
114
+ def GL_object_type
115
+ param_value = MemoryPointer.new( :cl_gl_object_type )
116
+ error = OpenCL.clGetGLObjectInfo( self, param_value, nil )
117
+ OpenCL.error_check(error)
118
+ return OpenCL::GLObjectType(param_value.read_cl_gl_object_type)
119
+ end
120
+
121
+ # Returns the name of the GL object associated with Mem
122
+ def GL_object_name
123
+ param_value = MemoryPointer.new( :cl_GLuint )
124
+ error = OpenCL.clGetGLObjectInfo( self, nil, param_value )
125
+ OpenCL.error_check(error)
126
+ return param_value.read_cl_GLuint
127
+ end
128
+
129
+ end
130
+
131
+ end
@@ -0,0 +1,119 @@
1
+ module OpenCL
2
+
3
+ # Returns an FFI::Function corresponding to an extension function
4
+ #
5
+ # ==== Attributes
6
+ #
7
+ # * +name+ - a String representing the name of the function
8
+ # * +return_type+ - the type of data returned by the function
9
+ # * +param_types+ - an Array of types, corresponding to the parameters type
10
+ # * +options+ - if given, a hash of named options that will be given to FFI::Function::new. See FFI doc for details.
11
+ def self.get_extension_function( name, return_type, param_types, options = {} )
12
+ name_p = FFI::MemoryPointer.from_string(name)
13
+ ptr = OpenCL.clGetExtensionFunctionAddress( name_p )
14
+ return nil if ptr.null?
15
+ return FFI::Function::new(return_type, param_types, ptr, options)
16
+ end
17
+
18
+ # Returns an Array of Platforms containing the available OpenCL platforms
19
+ def self.get_platforms
20
+ ptr1 = FFI::MemoryPointer.new(:cl_uint , 1)
21
+
22
+ error = OpenCL::clGetPlatformIDs(0, nil, ptr1)
23
+ OpenCL.error_check(error)
24
+ ptr2 = FFI::MemoryPointer.new(:pointer, ptr1.read_uint)
25
+ error = OpenCL::clGetPlatformIDs(ptr1.read_uint(), ptr2, nil)
26
+ OpenCL.error_check(error)
27
+ return ptr2.get_array_of_pointer(0,ptr1.read_uint()).collect { |platform_ptr|
28
+ OpenCL::Platform.new(platform_ptr)
29
+ }
30
+ end
31
+
32
+ # Returns an FFI::Function corresponding to an extension function for the Platform
33
+ #
34
+ # ==== Attributes
35
+ #
36
+ # * +platform+ - the Platform to be queried
37
+ # * +name+ - a String representing the name of the function
38
+ # * +return_type+ - the type of data returned by the function
39
+ # * +param_types+ - an Array of types, corresponding to the parameters type
40
+ # * +options+ - if given, a hash of named options that will be given to FFI::Function::new. See FFI doc for details.
41
+ def get_extension_function_for_platform( platform, name, return_type, param_types, options = {} )
42
+ OpenCL.error_check(OpenCL::INVALID_OPERATION) if self.version_number < 1.2
43
+ name_p = FFI::MemoryPointer.from_string(name)
44
+ ptr = OpenCL.clGetExtensionFunctionAddressForPlatform( platform, name_p )
45
+ return nil if ptr.null?
46
+ return FFI::Function::new(return_type, param_types, ptr, options)
47
+ end
48
+
49
+
50
+ # Maps the cl_platform_id object of OpenCL
51
+ class Platform
52
+ %w(PROFILE VERSION NAME VENDOR EXTENSIONS).each { |prop|
53
+ eval OpenCL.get_info("Platform", :string, prop)
54
+ }
55
+
56
+ # Returns an Array of Device corresponding to the available devices on the Platform
57
+ # The type of the desired devices can be specified
58
+ def devices(type = OpenCL::Device::Type::ALL)
59
+ ptr1 = FFI::MemoryPointer.new(:cl_uint , 1)
60
+ error = OpenCL::clGetDeviceIDs(self, type, 0, nil, ptr1)
61
+ OpenCL.error_check(error)
62
+ ptr2 = FFI::MemoryPointer.new(:pointer, ptr1.read_uint)
63
+ error = OpenCL::clGetDeviceIDs(self, type, ptr1.read_uint(), ptr2, nil)
64
+ OpenCL.error_check(error)
65
+ return ptr2.get_array_of_pointer(0, ptr1.read_uint()).collect { |device_ptr|
66
+ OpenCL::Device.new(device_ptr)
67
+ }
68
+ end
69
+
70
+ # returs a floating point number corresponding to the OpenCL version of the Platform
71
+ def version_number
72
+ ver = self.version
73
+ n = ver.scan(/OpenCL (\d+\.\d+)/)
74
+ return n.first.first.to_f
75
+ end
76
+
77
+ # Returns an FFI::Function corresponding to an extension function for a Platform
78
+ #
79
+ # ==== Attributes
80
+ #
81
+ # * +name+ - a String representing the name of the function
82
+ # * +return_type+ - the type of data returned by the function
83
+ # * +param_types+ - an Array of types, corresponding to the parameters type
84
+ # * +options+ - if given, a hash of named options that will be given to FFI::Function::new. See FFI doc for details.
85
+ def get_extension_function( name, return_type, param_types, options = {} )
86
+ OpenCL.error_check(OpenCL::INVALID_OPERATION) if self.version_number < 1.2
87
+ name_p = FFI::MemoryPointer.from_string(name)
88
+ ptr = OpenCL.clGetExtensionFunctionAddressForPlatform( self, name_p )
89
+ return nil if ptr.null?
90
+ return FFI::Function::new(return_type, param_types, ptr, options)
91
+ end
92
+
93
+ # Creates a Context gathering devices of a certain type and belonging to this Platform
94
+ #
95
+ # ==== Attributes
96
+ #
97
+ # * +type+ - type of device to be used
98
+ # * +options+ - if given, a hash of named options
99
+ # * +block+ - if provided, a callback invoked when error arise in the context. Signature of the callback is { |FFI::Pointer to null terminated c string, FFI::Pointer to binary data, :size_t number of bytes of binary data, FFI::Pointer to user_data| ... }
100
+ #
101
+ # ==== Options
102
+ #
103
+ # * +:properties+ - a list of :cl_context_properties, the Platform will be prepended
104
+ # * +:user_data+ - an FFI::Pointer or an object that can be converted into one using to_ptr. The pointer is passed to the callback.
105
+ def create_context_from_type(type, options = {}, &block)
106
+ props = [ OpenCL::Context::PLATFORM, self ]
107
+ if options[:properties] then
108
+ props = props + options[:properties]
109
+ else
110
+ props.push( 0 )
111
+ end
112
+ opts = options.clone
113
+ opts[:properties] = props
114
+ OpenCL.create_context_from_type(type, opts, &block)
115
+ end
116
+
117
+ end
118
+
119
+ end
@@ -0,0 +1,245 @@
1
+ module OpenCL
2
+
3
+ # Builds (compile and link) a Program created from sources or binary
4
+ #
5
+ # ==== Attributes
6
+ #
7
+ # * +program+ - the program to build
8
+ # * +options+ - a hash containing named options
9
+ # * +block+ - if provided, a callback invoked when the Program is built. Signature of the callback is { |Program, FFI::Pointer to user_data| ... }
10
+ #
11
+ # ==== Options
12
+ #
13
+ # * +:device_list+ - an Array of Device to build the program for
14
+ # * +:user_data+ - a Pointer (or convertible to Pointer using to_ptr) to the memory area to pass to the callback
15
+ # * +:options+ - a String containing the options to use for the build
16
+ def self.build_program(program, options = {}, &block)
17
+ @@callbacks.push( block ) if block
18
+ opt = ""
19
+ opt = options[:options] if options[:options]
20
+ options_p = FFI::MemoryPointer.from_string(opt)
21
+ devices = options[:device_list]
22
+ devices = [devices].flatten if devices
23
+ devices_p = nil
24
+ num_devices = 0
25
+ if devices and devices.size > 0 then
26
+ num_devices = devices.size
27
+ devices_p = FFI::MemoryPointer.new( Device, num_devices)
28
+ num_devices.times { |indx|
29
+ devices_p.put_pointer(indx, devices[indx])
30
+ }
31
+ end
32
+ err = OpenCL.clBuildProgram(program, num_devices, devices_p, options_p, block, options[:user_data] )
33
+ OpenCL.error_check(err)
34
+ return program
35
+ end
36
+
37
+ # Creates a Program from sources
38
+ #
39
+ # ==== Attributes
40
+ #
41
+ # * +context+ - Context the created Program will be associated to
42
+ # * +strings+ - a single or an Array of String repesenting the program source code
43
+ def self.create_program_with_source(context, strings)
44
+ strs = nil
45
+ if strings == nil then
46
+ raise OpenCL::Error::new(OpenCL::Error.getErrorString(OpenCL::Error::INVALID_VALUE))
47
+ else
48
+ strs = [strings].flatten
49
+ end
50
+ n_strs = strs.size
51
+ strs_lengths = FFI::MemoryPointer.new( :size_t, n_strs )
52
+ c_strs = FFI::MemoryPointer.new( :pointer, n_strs )
53
+
54
+ c_strs_p = []
55
+ strs.each { |str|
56
+ if str then
57
+ c_strs_p.push (FFI::MemoryPointer.from_string(str))
58
+ end
59
+ }
60
+ raise OpenCL::Error::new(OpenCL::Error.getErrorString(OpenCL::Error::INVALID_VALUE)) if c_strs_p.size == 0
61
+
62
+ c_strs = FFI::MemoryPointer.new( :pointer, c_strs_p.size )
63
+ c_strs_length = FFI::MemoryPointer.new( :size_t, c_strs_p.size )
64
+ c_strs_p.each_with_index { |p, i|
65
+ c_strs[i].write_pointer(p)
66
+ c_strs_length[i].write_size_t(p.size)
67
+ }
68
+ pointer_err = FFI::MemoryPointer.new( :cl_int )
69
+ program_ptr = OpenCL.clCreateProgramWithSource(context, c_strs_p.size, c_strs, c_strs_length, pointer_err)
70
+ OpenCL.error_check(pointer_err.read_cl_int)
71
+ return OpenCL::Program::new( program_ptr, false )
72
+ end
73
+
74
+ # Maps the cl_program object of OpenCL
75
+ class Program
76
+ alias_method :orig_method_missing, :method_missing
77
+
78
+ # Intercepts a call to a missing method and tries to see if it is defined as a Kernel inside
79
+ # the Program. It then calls the Kernel enqueue_with_args method. Thanks pyopencl (Andreas Klöeckner) for the idea
80
+ def method_missing(m, *a, &b)
81
+ m_string = m.to_s
82
+ k = nil
83
+ begin
84
+ k = self.create_kernel(m_string)
85
+ rescue OpenCL::Error
86
+ k = nil
87
+ end
88
+ if k then
89
+ k.enqueue_with_args(*a, &b)
90
+ else
91
+ orig_method_missing(m, *args, &b)
92
+ end
93
+ end
94
+ # Returns an Array containing the sizes of the binary inside the Program for each device
95
+ eval OpenCL.get_info_array("Program", :size_t, "BINARY_SIZES")
96
+
97
+ # Returns the number of Kernels defined in the Program
98
+ eval OpenCL.get_info("Program", :size_t, "NUM_KERNELS")
99
+
100
+ # Returns an Array of String representing the Kernel names inside the Program
101
+ def kernel_names
102
+ kernel_names_size = FFI::MemoryPointer.new( :size_t )
103
+ error = OpenCL.clGetProgramInfo( self, OpenCL::Program::KERNEL_NAMES, 0, nil, kernel_names_size)
104
+ OpenCL.error_check(error)
105
+ k_names = FFI::MemoryPointer.new( kernel_names_size.read_size_t )
106
+ error = OpenCL.clGetProgramInfo( self, OpenCL::Program::KERNEL_NAMES, kernel_names_size.read_size_t, k_names, nil)
107
+ OpenCL.error_check(error)
108
+ k_names_string = k_names.read_string
109
+ returns k_names_string.split(";")
110
+ end
111
+
112
+ # Returns the concatenated Program sources
113
+ eval OpenCL.get_info("Program", :string, "SOURCE")
114
+
115
+ # Returns the BuildStatus of the Program
116
+ def build_status(devs = nil)
117
+ devs = self.devices if not devs
118
+ devs = [devs].flatten
119
+ ptr = FFI::MemoryPointer.new( :cl_build_status )
120
+ return devs.collect { |dev|
121
+ error = OpenCL.clGetProgramBuildInfo(self, dev, OpenCL::Program::BUILD_STATUS, ptr.size, ptr, nil)
122
+ OpenCL.error_check(error)
123
+ OpenCL::BuildStatus::new(ptr.read_cl_build_status)
124
+ }
125
+ end
126
+
127
+ # Returns the BinaryType for each Device associated to the Program or the Device specified
128
+ def binary_type(devs = nil)
129
+ devs = self.devices if not devs
130
+ devs = [devs].flatten
131
+ ptr = FFI::MemoryPointer.new( :cl_program_binary_type )
132
+ return devs.collect { |dev|
133
+ error = OpenCL.clGetProgramBuildInfo(self, dev, OpenCL::Program::BINARY_TYPE, ptr.size, ptr, nil)
134
+ OpenCL.error_check(error)
135
+ OpenCL::Program::BinaryType::new(ptr.read_cl_program_binary_type)
136
+ }
137
+ end
138
+
139
+ # Returns the build options for each Device associated to the Program or the Device specified
140
+ def build_options(devs = nil)
141
+ devs = self.devices if not devs
142
+ devs = [devs].flatten
143
+ return devs.collect { |dev|
144
+ ptr1 = FFI::MemoryPointer.new( :size_t, 1)
145
+ error = OpenCL.clGetProgramBuildInfo(self, dev, OpenCL::Program::BUILD_OPTIONS, 0, nil, ptr1)
146
+ OpenCL.error_check(error)
147
+ ptr2 = FFI::MemoryPointer.new( ptr1.read_size_t )
148
+ error = OpenCL.clGetProgramBuildInfo(self, dev, OpenCL::Program::BUILD_OPTIONS, ptr1.read_size_t, ptr2, nil)
149
+ OpenCL.error_check(error)
150
+ ptr2.read_string
151
+ }
152
+ end
153
+
154
+ # Returns the build log for each Device associated to the Program or the Device specified
155
+ def build_log(devs = nil)
156
+ devs = self.devices if not devs
157
+ devs = [devs].flatten
158
+ return devs.collect { |dev|
159
+ ptr1 = FFI::MemoryPointer.new( :size_t, 1)
160
+ error = OpenCL.clGetProgramBuildInfo(self, dev, OpenCL::Program::BUILD_LOG, 0, nil, ptr1)
161
+ OpenCL.error_check(error)
162
+ ptr2 = FFI::MemoryPointer.new( ptr1.read_size_t )
163
+ error = OpenCL.clGetProgramBuildInfo(self, dev, OpenCL::Program::BUILD_LOG, ptr1.read_size_t, ptr2, nil)
164
+ OpenCL.error_check(error)
165
+ ptr2.read_string
166
+ }
167
+ end
168
+
169
+ # Returns the binaries associated to the Program for each Device
170
+ def binaries
171
+ sizes = self.binary_sizes
172
+ bin_array = FFI::MemoryPointer.new( :pointer, sizes.length )
173
+ sizes.length
174
+ total_size = 0
175
+ sizes.each_with_index { |s, i|
176
+ total_size += s
177
+ bin_array[i].write_pointer(FFI::MemoryPointer.new(s))
178
+ }
179
+ error = OpenCL.clGetProgramInfo(self, Program::BINARIES, total_size, bin_array, nil)
180
+ OpenCL.error_check(error)
181
+ bins = []
182
+ sizes.each_with_index { |s, i|
183
+ bins.push bin_array[i].read_pointer.read_bytes(s)
184
+ }
185
+ return bins
186
+ end
187
+
188
+ # Builds (compile and link) the Program created from sources or binary
189
+ #
190
+ # ==== Attributes
191
+ #
192
+ # * +options+ - a hash containing named options
193
+ # * +block+ - if provided, a callback invoked when error arise in the context. Signature of the callback is { |Program, FFI::Pointer to user_data| ... }
194
+ #
195
+ # ==== Options
196
+ # * +:device_list+ - an Array of Device to build the program for
197
+ # * +:user_data+ - a Pointer (or convertible to Pointer using to_ptr) to the memory area to pass to the callback
198
+ # * +:options+ - a String containing the options to use for the build
199
+ def build(options = { }, &block)
200
+ OpenCL.build_program(self, options, &block)
201
+ end
202
+
203
+ # Returns the Context the Program is associated to
204
+ def context
205
+ ptr = FFI::MemoryPointer.new( Context )
206
+ error = OpenCL.clGetProgramInfo(self, Program::CONTEXT, Context.size, ptr, nil)
207
+ OpenCL.error_check(error)
208
+ return OpenCL::Context::new( ptr.read_pointer )
209
+ end
210
+
211
+ ##
212
+ # :method: num_devices()
213
+ # Returns the number of device this Program is associated with
214
+
215
+ ##
216
+ # :method: reference_count()
217
+ # Returns the reference counter for this Program
218
+ %w( NUM_DEVICES REFERENCE_COUNT ).each { |prop|
219
+ eval OpenCL.get_info("Program", :cl_uint, prop)
220
+ }
221
+
222
+ # Returns the Array of Device the Program is associated with
223
+ def devices
224
+ n = self.num_devices
225
+ ptr2 = FFI::MemoryPointer.new( Device, n )
226
+ error = OpenCL.clGetProgramInfo(self, Program::DEVICES, Device.size*n, ptr2, nil)
227
+ OpenCL.error_check(error)
228
+ return ptr2.get_array_of_pointer(0, n).collect { |device_ptr|
229
+ OpenCL::Device.new(device_ptr)
230
+ }
231
+ end
232
+
233
+ # Returns the Kernel corresponding the the specified name in the Program
234
+ def create_kernel( name )
235
+ return OpenCL.create_kernel( self, name )
236
+ end
237
+
238
+ # Returns an Array of Kernel corresponding to the kernels defined inside the Program
239
+ def kernels
240
+ return OpenCL.create_kernels_in_program( self )
241
+ end
242
+
243
+ end
244
+
245
+ end