--- OpenCL/OpenCL.pm 2011/11/22 10:39:47 1.25 +++ OpenCL/OpenCL.pm 2012/04/24 14:24:42 1.52 @@ -107,7 +107,7 @@ printf "extensions: %s\n", $platform->extensions; for my $device ($platform->devices) { printf "+ device: %s\n", $device->name; - my $ctx = $device->context; + my $ctx = $platform->context (undef, [$device]); # do stuff } } @@ -151,20 +151,15 @@ functions. my $src = ' - __kernel void - squareit (__global float *input, __global float *output) + kernel void + squareit (global float *input, global float *output) { $id = get_global_id (0); output [id] = input [id] * input [id]; } '; - my $prog = $ctx->program_with_source ($src); - - # build croaks on compile errors, so catch it and print the compile errors - eval { $prog->build ($dev); 1 } - or die $prog->build_log; - + my $prog = $ctx->build_program ($src); my $kernel = $prog->kernel ("squareit"); =head2 Create some input and output float buffers, then call the @@ -213,6 +208,99 @@ # wait for the last event to complete $ev->wait; +=head2 Use the OpenGL module to share a texture between OpenCL and OpenGL and draw some julia +set tunnel effect. + +This is quite a long example to get you going. + + use OpenGL ":all"; + use OpenCL; + + # open a window and create a gl texture + OpenGL::glpOpenWindow width => 256, height => 256; + my $texid = glGenTextures_p 1; + glBindTexture GL_TEXTURE_2D, $texid; + glTexImage2D_c GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0; + + # find and use the first opencl device that let's us get a shared opengl context + my $platform; + my $dev; + my $ctx; + + for (OpenCL::platforms) { + $platform = $_; + for ($platform->devices) { + $dev = $_; + $ctx = $platform->context ([OpenCL::GLX_DISPLAY_KHR, undef, OpenCL::GL_CONTEXT_KHR, undef], [$dev]) + and last; + } + } + + $ctx + or die "cannot find suitable OpenCL device\n"; + + my $queue = $ctx->queue ($dev); + + # now attach an opencl image2d object to the opengl texture + my $tex = $ctx->gl_texture2d (OpenCL::MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, $texid); + + # now the boring opencl code + my $src = <build_program ($src); + my $kernel = $prog->kernel ("juliatunnel"); + + # program compiled, kernel ready, now draw and loop + + for (my $time; ; ++$time) { + # acquire objects from opengl + $queue->enqueue_acquire_gl_objects ([$tex]); + + # configure and run our kernel + $kernel->set_image2d (0, $tex); + $kernel->set_float (1, $time); + $queue->enqueue_nd_range_kernel ($kernel, undef, [256, 256], undef); + + # release objects to opengl again + $queue->enqueue_release_gl_objects ([$tex]); + + # wait + $queue->finish; + + # now draw the texture, the defaults should be all right + glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST; + + glEnable GL_TEXTURE_2D; + glBegin GL_QUADS; + glTexCoord2f 0, 1; glVertex3i -1, -1, -1; + glTexCoord2f 0, 0; glVertex3i 1, -1, -1; + glTexCoord2f 1, 0; glVertex3i 1, 1, -1; + glTexCoord2f 1, 1; glVertex3i -1, 1, -1; + glEnd; + + glXSwapBuffers; + + select undef, undef, undef, 1/60; + } + =head1 DOCUMENTATION =head2 BASIC CONVENTIONS @@ -243,7 +331,9 @@ =item * When enqueuing commands, the wait list is specified by adding extra arguments to the function - anywhere a C<$wait_events...> argument -is documented this can be any number of event objects. +is documented this can be any number of event objects. As an extsnion +implemented by this module, C values will be ignored in the event +list. =item * When enqueuing commands, if the enqueue method is called in void context, no event is created. In all other contexts an event is returned @@ -273,6 +363,58 @@ half IV ushort S double NV double d +=head2 GLX SUPPORT + +Due to the sad state that OpenGL support is in in Perl (mostly the OpenGL +module, which has little to no documentation and has little to no support +for glX), this module, as a special extension, treats context creation +properties C and C +specially: If either or both of these are C, then the OpenCL +module tries to dynamically resolve C and +C, call these functions and use their return values +instead. + +For this to work, the OpenGL library must be loaded, a GLX context must +have been created and be made current, and C must be available and +capable of finding the function via C. + +=cut + +package OpenCL; + +use common::sense; + +BEGIN { + our $VERSION = '0.96'; + + require XSLoader; + XSLoader::load (__PACKAGE__, $VERSION); + + @OpenCL::Platform::ISA = + @OpenCL::Device::ISA = + @OpenCL::Context::ISA = + @OpenCL::Queue::ISA = + @OpenCL::Memory::ISA = + @OpenCL::Sampler::ISA = + @OpenCL::Program::ISA = + @OpenCL::Kernel::ISA = + @OpenCL::Event::ISA = OpenCL::Object::; + + @OpenCL::Buffer::ISA = + @OpenCL::Image::ISA = OpenCL::Memory::; + + @OpenCL::BufferObj::ISA = OpenCL::Buffer::; + + @OpenCL::Image2D::ISA = + @OpenCL::Image3D::ISA = + @OpenCL::Image2DArray::ISA = + @OpenCL::Image1D::ISA = + @OpenCL::Image1DArray::ISA = + @OpenCL::Image1DBuffer::ISA = OpenCL::Image::; + + @OpenCL::UserEvent::ISA = OpenCL::Event::; +} + =head2 THE OpenCL PACKAGE =over 4 @@ -288,9 +430,9 @@ =item $str = OpenCL::enum2str $enum -Converts most enum values (inof parameter names, image format constants, +Converts most enum values (of parameter names, image format constants, object types, addressing and filter modes, command types etc.) into a -human readbale string. When confronted with some random integer it can be +human readable string. When confronted with some random integer it can be very helpful to pass it through this function to maybe get some readable string out of it. @@ -314,6 +456,29 @@ =back +=head2 THE OpenCL::Object CLASS + +This is the base class for all objects in the OpenCL module. The only +method it implements is the C method, which is only useful if you want +to interface to OpenCL on the C level. + +=over 4 + +=item $iv = $obj->id + +OpenCL objects are represented by pointers or integers on the C level. If +you want to interface to an OpenCL object directly on the C level, then +you need this value, which is returned by this method. You should use an +C type in your code and cast that to the correct type. + +=cut + +sub OpenCL::Object::id { + ${$_[0]} +} + +=back + =head2 THE OpenCL::Platform CLASS =over 4 @@ -328,7 +493,7 @@ L -=item $ctx = $device->context ($properties = undef, @$devices, $notify = undef) +=item $ctx = $platform->context ($properties = undef, @$devices, $notify = undef) Create a new OpenCL::Context object using the given device object(s)- a CL_CONTEXT_PLATFORM property is supplied automatically. @@ -346,6 +511,13 @@ L +=item $platform->unload_compiler + +Attempts to unload the compiler for this platform, for endless +profit. Does nothing on OpenCL 1.1. + +L + =for gengetinfo begin platform =item $string = $platform->profile @@ -640,9 +812,9 @@ Calls C with C and returns the result. -=item $uint = $device->reference_count_ext +=item $uint = $device->reference_count_ext -Calls C with C and returns the result. +Calls C with C and returns the result. =item @device_partition_property_exts = $device->partition_style_ext @@ -656,12 +828,43 @@ =over 4 +=item $prog = $ctx->build_program ($program, $options = "") + +This convenience function tries to build the program on all devices in +the context. If the build fails, then the function will C with the +build log. Otherwise ti returns the program object. + +The C<$program> can either be a C object or a string +containing the program. In the latter case, a program objetc will be +created automatically. + +=cut + +sub OpenCL::Context::build_program { + my ($self, $prog, $options) = @_; + + $prog = $self->program_with_source ($prog) + unless ref $prog; + + for my $dev ($self->devices) { + eval { $prog->build ($dev, $options); 1 } + or Carp::croak "Building OpenCL program for device '" . $dev->name . "' failed:\n" + . $prog->build_log ($dev); + } + + $prog +} + =item $queue = $ctx->queue ($device, $properties) Create a new OpenCL::Queue object from the context and the given device. L +Example: create an out-of-order queue. + + $queue = $ctx->queue ($device, OpenCL::QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE); + =item $ev = $ctx->user_event Creates a new OpenCL::UserEvent object. @@ -670,26 +873,72 @@ =item $buf = $ctx->buffer ($flags, $len) -Creates a new OpenCL::Buffer object with the given flags and octet-size. +Creates a new OpenCL::Buffer (actually OpenCL::BufferObj) object with the +given flags and octet-size. L =item $buf = $ctx->buffer_sv ($flags, $data) -Creates a new OpenCL::Buffer object and initialise it with the given data values. +Creates a new OpenCL::Buffer (actually OpenCL::BufferObj) object and +initialise it with the given data values. + +=item $img = $ctx->image ($self, $flags, $channel_order, $channel_type, $type, $width, $height, $depth, $array_size = 0, $row_pitch = 0, $slice_pitch = 0, $num_mip_level = 0, $num_samples = 0, $*data = &PL_sv_undef) + +Creates a new OpenCL::Image object and optionally initialises it with +the given data values. + +L =item $img = $ctx->image2d ($flags, $channel_order, $channel_type, $width, $height, $row_pitch = 0, $data = undef) -Creates a new OpenCL::Image2D object and optionally initialises it with the given data values. +Creates a new OpenCL::Image2D object and optionally initialises it with +the given data values. L =item $img = $ctx->image3d ($flags, $channel_order, $channel_type, $width, $height, $depth, $row_pitch = 0, $slice_pitch = 0, $data = undef) -Creates a new OpenCL::Image3D object and optionally initialises it with the given data values. +Creates a new OpenCL::Image3D object and optionally initialises it with +the given data values. L +=item $buffer = $ctx->gl_buffer ($flags, $bufobj) + +Creates a new OpenCL::Buffer (actually OpenCL::BufferObj) object that refers to the given +OpenGL buffer object. + +http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateFromGLBuffer.html + +=item $img = $ctx->gl_texture ($flags, $target, $miplevel, $texture) + +Creates a new OpenCL::Image object that refers to the given OpenGL +texture object or buffer. + +http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateFromGLTexture.html + +=item $img = $ctx->gl_texture2d ($flags, $target, $miplevel, $texture) + +Creates a new OpenCL::Image2D object that refers to the given OpenGL +2D texture object. + +http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateFromGLTexture2D.html + +=item $img = $ctx->gl_texture3d ($flags, $target, $miplevel, $texture) + +Creates a new OpenCL::Image3D object that refers to the given OpenGL +3D texture object. + +http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateFromGLTexture3D.html + +=item $ctx->gl_renderbuffer ($flags, $renderbuffer) + +Creates a new OpenCL::Image2D object that refers to the given OpenGL +render buffer. + +http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateFromGLRenderbuffer.html + =item @formats = $ctx->supported_image_formats ($flags, $image_type) Returns a list of matching image formats - each format is an arrayref with @@ -749,11 +998,17 @@ They also allow you to specify any number of other event objects that this request has to wait for before it starts executing, by simply passing the -event objects as extra parameters to the enqueue methods. +event objects as extra parameters to the enqueue methods. To simplify +program design, this module ignores any C values in the list of +events. This makes it possible to code operations such as this, without +having to put a valid event object into C<$event> first: + + $event = $queue->enqueue_xxx (..., $event); Queues execute in-order by default, without any parallelism, so in most cases (i.e. you use only one queue) it's not necessary to wait for or -create event objects. +create event objects, althoguh an our of order queue is often a bit +faster. =over 4 @@ -783,29 +1038,45 @@ =item $ev = $queue->enqueue_read_image ($src, $blocking, $x, $y, $z, $width, $height, $depth, $row_pitch, $slice_pitch, $data, $wait_events...) +L + +=item $ev = $queue->enqueue_copy_buffer_to_image ($src_buffer, $dst_image, $src_offset, $dst_x, $dst_y, $dst_z, $width, $height, $depth, $wait_events...) + L =item $ev = $queue->enqueue_write_image ($src, $blocking, $x, $y, $z, $width, $height, $depth, $row_pitch, $slice_pitch, $data, $wait_events...) L +=item $ev = $queue->enqueue_copy_image ($src_image, $dst_image, $src_x, $src_y, $src_z, $dst_x, $dst_y, $dst_z, $width, $height, $depth, $wait_events...) + +L + +=item $ev = $queue->enqueue_copy_image_to_buffer ($src_image, $dst_image, $src_x, $src_y, $src_z, $width, $height, $depth, $dst_offset, $wait_events...) + +L + =item $ev = $queue->enqueue_copy_buffer_rect ($src, $dst, $src_x, $src_y, $src_z, $dst_x, $dst_y, $dst_z, $width, $height, $depth, $src_row_pitch, $src_slice_pitch, $dst_row_pitch, $dst_slice_pitch, $wait_event...) Yeah. -L +L. -=item $ev = $queue->enqueue_copy_buffer_to_image ($src_buffer, $dst_image, $src_offset, $dst_x, $dst_y, $dst_z, $width, $height, $depth, $wait_events...) +=item $ev = $queue->enqueue_fill_buffer ($mem, $pattern, $offset, $size, ...) -L. +Fills the given buffer object with repeated applications of C<$pattern>, +starting at C<$offset> for C<$size> octets. -=item $ev = $queue->enqueue_copy_image ($src_image, $dst_image, $src_x, $src_y, $src_z, $dst_x, $dst_y, $dst_z, $width, $height, $depth, $wait_events...) +L -L +=item $ev = $queue->enqueue_fill_image ($img, $r, $g, $b, $a, $x, $y, $z, $width, $height, $depth, ...) -=item $ev = $queue->enqueue_copy_image_to_buffer ($src_image, $dst_image, $src_x, $src_y, $src_z, $width, $height, $depth, $dst_offset, $wait_events...) +Fills the given image area with the given rgba colour components. The +components are normally floating point values between C<0> and C<1>, +except when the image channel data type is a signe dor unsigned +unnormalised format, in which case the range is determined by the format. -L +L =item $ev = $queue->enqueue_task ($kernel, $wait_events...) @@ -829,17 +1100,31 @@ L -=item $ev = $queue->enqueue_marker +=item $ev = $queue->enqueue_acquire_gl_objects ([object, ...], $wait_events...) + +Enqueues a list (an array-ref of OpenCL::Memory objects) to be acquired +for subsequent OpenCL usage. + +L + +=item $ev = $queue->enqueue_release_gl_objects ([object, ...], $wait_events...) + +Enqueues a list (an array-ref of OpenCL::Memory objects) to be released +for subsequent OpenGL usage. -L +L =item $ev = $queue->enqueue_wait_for_events ($wait_events...) L -=item $queue->enqueue_barrier +=item $ev = $queue->enqueue_marker ($wait_events...) -L +L + +=item $ev = $queue->enqueue_barrier ($wait_events...) + +L =item $queue->flush @@ -930,11 +1215,43 @@ =for gengetinfo end mem +=item ($type, $name) = $mem->gl_object_info + +Returns the OpenGL object type (e.g. OpenCL::GL_OBJECT_TEXTURE2D) and the +object "name" (e.g. the texture name) used to create this memory object. + +L + +=back + +=head2 THE OpenCL::Buffer CLASS + +This is a subclass of OpenCL::Memory, and the superclass of +OpenCL::BufferObj. Its purpose is simply to distinguish between buffers +and sub-buffers. + +=head2 THE OpenCL::BufferObj CLASS + +This is a subclass of OpenCL::Buffer and thus OpenCL::Memory. It exists +because one cna create sub buffers of OpenLC::BufferObj objects, but not +sub buffers from these sub buffers. + +=over 4 + +=item $subbuf = $buf_obj->sub_buffer_region ($flags, $origin, $size) + +Creates an OpenCL::Buffer objects from this buffer and returns it. The +C is assumed to be C. + +L + =back =head2 THE OpenCL::Image CLASS -This is the superclass of all image objects - OpenCL::Image2D and OpenCL::Image3D. +This is the superclass of all image objects - OpenCL::Image1D, +OpenCL::Image1DArray, OpenCL::Image1DBuffer, OpenCL::Image2D, +OpenCL::Image2DArray and OpenCL::Image3D. =over 4 @@ -975,6 +1292,18 @@ =for gengetinfo end image +=for gengetinfo begin gl_texture + +=item $GLenum = $gl_texture->target + +Calls C with C and returns the result. + +=item $GLint = $gl_texture->gl_mipmap_level + +Calls C with C and returns the result. + +=for gengetinfo end gl_texture + =back =head2 THE OpenCL::Sampler CLASS @@ -1019,7 +1348,8 @@ =item $program->build ($device, $options = "") -Tries to build the program with the givne options. +Tries to build the program with the given options. See also the +C<$ctx->build> convenience function. L @@ -1037,6 +1367,12 @@ L +=item @kernels = $program->kernels_in_program + +Returns all kernels successfully compiled for all devices in program. + +http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateKernelsInProgram.html + =for gengetinfo begin program_build =item $build_status = $program->build_status ($device) @@ -1173,12 +1509,17 @@ TYPE is one of C, C, C, C, C, C, C, C, C, C, C, C, C, -C, C, C or C. +C, C, C, C or C. Chars and integers (including the half type) are specified as integers, float and double as floating point values, memory/buffer/image2d/image3d -must be an object of that type or C, and sampler and event must be -objects of that type. +must be an object of that type or C, local-memory arguments are +set by specifying the size, and sampler and event must be objects of that +type. + +Setting an argument for a kernel does NOT keep a reference to the object - +for example, if you set an argument to some image object, free the image, +and call the kernel, you will run into undefined behaviour. L @@ -1272,25 +1613,6 @@ =cut -package OpenCL; - -use common::sense; - -BEGIN { - our $VERSION = '0.55'; - - require XSLoader; - XSLoader::load (__PACKAGE__, $VERSION); - - @OpenCL::Buffer::ISA = - @OpenCL::Image::ISA = OpenCL::Memory::; - - @OpenCL::Image2D::ISA = - @OpenCL::Image3D::ISA = OpenCL::Image::; - - @OpenCL::UserEvent::ISA = OpenCL::Event::; -} - 1; =head1 AUTHOR