-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpycl.py
executable file
·3186 lines (2919 loc) · 128 KB
/
pycl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python
"""
Brief usage example::
from pycl import *
from array import array
source = '''
kernel void mxplusb(float m, global float *x, float b, global float *out) {
int i = get_global_id(0);
out[i] = m*x[i]+b;
}
'''
ctx = clCreateContext()
queue = clCreateCommandQueue(ctx)
program = clCreateProgramWithSource(ctx, source).build()
kernel = program['mxplusb']
kernel.argtypes = (cl_float, cl_mem, cl_float, cl_mem)
x = array('f', range(10))
x_buf, in_evt = buffer_from_pyarray(queue, x, blocking=False)
y_buf = x_buf.empty_like_this()
run_evt = kernel(2, x_buf, 5, y_buf).on(queue, len(x), wait_for=in_evt)
y, evt = buffer_to_pyarray(queue, y_buf, wait_for=run_evt, like=x)
evt.wait()
print y
For Numpy users, see :func:`buffer_from_ndarray` and
:func:`buffer_to_ndarray`.
Additionally, if run as a script, will print out a summary
of your platforms and devices.
Most of the C typedefs are available as subclasses of
Python ctypes datatypes. The spelling might be slightly
different.
The various enumeration and bitfield types have attributes
representing their defined constants (e.g.
:const:`~cl_device_type.CL_DEVICE_TYPE_GPU`). These
constants are also available at the module level, in case
you can't remember what type
:const:`~cl_command_execution_status.CL_QUEUED` is supposed
to be. They are all somewhat magical in that they'll
make a reasonable effort to pretty-print themselves:
>>> cl_device_type.CL_DEVICE_TYPE_GPU | cl_device_type.CL_DEVICE_TYPE_CPU
CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU
>>> cl_mem_info(0x1100)
CL_MEM_TYPE
The types representing various object-like datastructures
often have attributes so that you can view their infos
without needing to call the appropriate ``clGetThingInfo``
function. They may have other methods and behaviors.
One last note about the datatypes: despite any appearance
of magic and high-level function, these are just ctypes
objects. It is entirely possible for you to assign things
to the :attr:`value` attribute of the enum/bitfield
constants or of object-like items. Overwriting constants
and clobbering pointers is generally a bad idea, though,
so you should probably avoid it. (I tried vetoing
assignment to .value, but PyPy didn't like that.
So you're on your own.)
Wrapped OpenCL functions have their usual naming convention
(``clDoSomething``). These are't the naked C function
pointers - you will find that the argument lists,
return types, and exception raising are more in line with
Python. Check the docstrings. That said, you can refer to
the function pointer itself with the wrapped function's
:attr:`call` attribute, which is how the functions
themselves do it. The function pointer itself has argument
type, return type, and error checking added in the usual
ctypes manner.
The list of wrapped functions is *very* incomplete. Feel
free to contribute if you need a function that hasn't been
wrapped yet.
There are currently no plans to provide wrappers for OpenCL
extensions (like OpenGL interop). Maybe later.
"""
# Copyright (c) 2011 Ken Watford
#
# 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 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.
#
# tl;dr - MIT license.
__version__ = '0.1.2'
import ctypes
import _ctypes
from ctypes import (
c_size_t as size_t, c_void_p, c_char_p as char_p,
POINTER as P, byref, sizeof, pointer, cast, create_string_buffer)
import os
import sys
from warnings import warn
from array import array
try:
import numpy as np
except ImportError:
np = None
pass
class void_p(c_void_p):
# base class for various objects in OpenCL.
def __eq__(self, o):
"""True iff the object we wrap is the same (accd to pointer equality)."""
try:
return self.value == o.value
except AttributeError:
return False
class cl_sampler(void_p): pass
class cl_char(ctypes.c_int8): pass
class cl_uchar(ctypes.c_uint8): pass
class cl_short(ctypes.c_int16): pass
class cl_ushort(ctypes.c_uint16): pass
class cl_int(ctypes.c_int32): pass
class cl_uint(ctypes.c_uint32): pass
class cl_long(ctypes.c_int64): pass
class cl_ulong(ctypes.c_uint64): pass
class cl_half(ctypes.c_uint16): pass
class cl_float(ctypes.c_float): pass
class cl_double(ctypes.c_double): pass
class cl_bool(cl_uint): pass
class cl_uenum(cl_uint):
# Base class for the various unsigned int
# constants defined in OpenCL.
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
else:
return self.value == other.value
def __ne__(self, other):
return not(self == other)
def __hash__(self):
return self.value.__hash__()
def __repr__(self):
by_value = self.__class__._by_value
names = []
if self in by_value:
return by_value[self]
elif self.value:
return "UNKNOWN(0%x)" % self.value
else:
return "NONE"
class cl_enum(cl_int):
# Base class for various signed int enums.
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
else:
return self.value == other.value
def __ne__(self, other):
return not(self == other)
def __hash__(self):
return self.value.__hash__()
def __repr__(self):
by_value = self.__class__._by_value
names = []
if self in by_value:
return by_value[self]
elif self.value:
return "UNKNOWN(0x%x)" % self.value
else:
return "NONE"
class cl_bitfield(cl_ulong):
# Base class for bitfield values found in OpenCL.
# Bitwise operations for combining flags are supported.
def __or__(self, other):
assert isinstance(other, self.__class__)
return self.__class__(self.value | other.value)
def __and__(self, other):
assert isinstance(other, self.__class__)
return self.__class__(self.value & other.value)
def __xor__(self, other):
assert isinstance(other, self.__class__)
return self.__class__(self.value ^ other.value)
def __not__(self):
return self.__class__(~self.value)
def __contains__(self, other):
assert isinstance(other, self.__class__)
return (self.value & other.value) == other.value
def __hash__(self):
return self.value.__hash__()
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
else:
return self.value == other.value
def __ne__(self, other):
return not(self == other)
def __repr__(self):
by_value = self.__class__._by_value
names = []
if self in by_value:
return by_value[self]
for val in by_value:
if val in self:
names.append(by_value[val])
if names:
return " | ".join(names)
elif self.value:
return "UNKNOWN(0x%x)" % self.value
else:
return "NONE"
class cl_device_type(cl_bitfield):
"""
Bitfield used by :func:`clCreateContextFromType` to
create a context from one or more matching device types.
See also :attr:`cl_device.type` and :func:`clGetDeviceInfo`
"""
CL_DEVICE_TYPE_DEFAULT = (1 << 0)
CL_DEVICE_TYPE_CPU = (1 << 1)
CL_DEVICE_TYPE_GPU = (1 << 2)
CL_DEVICE_TYPE_ACCELERATOR = (1 << 3)
CL_DEVICE_TYPE_ALL = 0xFFFFFFFF
class cl_errnum(cl_enum):
"""
A status code returned by most OpenCL functions.
Exceptions exist for each error code and will be
raised in the event that the code is flagged by
any wrapper function. The exception names are formed
by removing the 'CL', title-casing the words, removing
the underscores, and appending 'Error' to the end.
Some of these are a little redundant, like
:exc:`BuildProgramFailureError`.
And no, there is no :exc:`SuccessError`.
"""
CL_SUCCESS = 0
CL_DEVICE_NOT_FOUND = -1
CL_DEVICE_NOT_AVAILABLE = -2
CL_COMPILER_NOT_AVAILABLE = -3
CL_MEM_OBJECT_ALLOCATION_FAILURE = -4
CL_OUT_OF_RESOURCES = -5
CL_OUT_OF_HOST_MEMORY = -6
CL_PROFILING_INFO_NOT_AVAILABLE = -7
CL_MEM_COPY_OVERLAP = -8
CL_IMAGE_FORMAT_MISMATCH = -9
CL_IMAGE_FORMAT_NOT_SUPPORTED = -10
CL_BUILD_PROGRAM_FAILURE = -11
CL_MAP_FAILURE = -12
CL_MISALIGNED_SUB_BUFFER_OFFSET = -13
CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST = -14
CL_COMPILE_PROGRAM_FAILURE = -15
CL_LINKER_NOT_AVAILABLE = -16
CL_LINK_PROGRAM_FAILURE = -17
CL_DEVICE_PARTITION_FAILED = -18
CL_KERNEL_ARG_INFO_NOT_AVAILABLE = -19
CL_INVALID_VALUE = -30
CL_INVALID_DEVICE_TYPE = -31
CL_INVALID_PLATFORM = -32
CL_INVALID_DEVICE = -33
CL_INVALID_CONTEXT = -34
CL_INVALID_QUEUE_PROPERTIES = -35
CL_INVALID_COMMAND_QUEUE = -36
CL_INVALID_HOST_PTR = -37
CL_INVALID_MEM_OBJECT = -38
CL_INVALID_IMAGE_FORMAT_DESCRIPTOR = -39
CL_INVALID_IMAGE_SIZE = -40
CL_INVALID_SAMPLER = -41
CL_INVALID_BINARY = -42
CL_INVALID_BUILD_OPTIONS = -43
CL_INVALID_PROGRAM = -44
CL_INVALID_PROGRAM_EXECUTABLE = -45
CL_INVALID_KERNEL_NAME = -46
CL_INVALID_KERNEL_DEFINITION = -47
CL_INVALID_KERNEL = -48
CL_INVALID_ARG_INDEX = -49
CL_INVALID_ARG_VALUE = -50
CL_INVALID_ARG_SIZE = -51
CL_INVALID_KERNEL_ARGS = -52
CL_INVALID_WORK_DIMENSION = -53
CL_INVALID_WORK_GROUP_SIZE = -54
CL_INVALID_WORK_ITEM_SIZE = -55
CL_INVALID_GLOBAL_OFFSET = -56
CL_INVALID_EVENT_WAIT_LIST = -57
CL_INVALID_EVENT = -58
CL_INVALID_OPERATION = -59
CL_INVALID_GL_OBJECT = -60
CL_INVALID_BUFFER_SIZE = -61
CL_INVALID_MIP_LEVEL = -62
CL_INVALID_GLOBAL_WORK_SIZE = -63
CL_INVALID_PROPERTY = -64
CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR = -1000
class cl_platform_info(cl_uenum):
"""
The set of possible parameter names used
with the :func:`clGetPlatformInfo` function.
"""
CL_PLATFORM_PROFILE = 0x0900
CL_PLATFORM_VERSION = 0x0901
CL_PLATFORM_NAME = 0x0902
CL_PLATFORM_VENDOR = 0x0903
CL_PLATFORM_EXTENSIONS = 0x0904
class cl_device_info(cl_uenum):
"""
The set of possible parameter names used
with the :func:`clGetDeviceInfo` function.
"""
CL_DEVICE_TYPE = 0x1000
CL_DEVICE_VENDOR_ID = 0x1001
CL_DEVICE_MAX_COMPUTE_UNITS = 0x1002
CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS = 0x1003
CL_DEVICE_MAX_WORK_GROUP_SIZE = 0x1004
CL_DEVICE_MAX_WORK_ITEM_SIZES = 0x1005
CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR = 0x1006
CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT = 0x1007
CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT = 0x1008
CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG = 0x1009
CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT = 0x100A
CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE = 0x100B
CL_DEVICE_MAX_CLOCK_FREQUENCY = 0x100C
CL_DEVICE_ADDRESS_BITS = 0x100D
CL_DEVICE_MAX_READ_IMAGE_ARGS = 0x100E
CL_DEVICE_MAX_WRITE_IMAGE_ARGS = 0x100F
CL_DEVICE_MAX_MEM_ALLOC_SIZE = 0x1010
CL_DEVICE_IMAGE2D_MAX_WIDTH = 0x1011
CL_DEVICE_IMAGE2D_MAX_HEIGHT = 0x1012
CL_DEVICE_IMAGE3D_MAX_WIDTH = 0x1013
CL_DEVICE_IMAGE3D_MAX_HEIGHT = 0x1014
CL_DEVICE_IMAGE3D_MAX_DEPTH = 0x1015
CL_DEVICE_IMAGE_SUPPORT = 0x1016
CL_DEVICE_MAX_PARAMETER_SIZE = 0x1017
CL_DEVICE_MAX_SAMPLERS = 0x1018
CL_DEVICE_MEM_BASE_ADDR_ALIGN = 0x1019
CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE = 0x101A
CL_DEVICE_SINGLE_FP_CONFIG = 0x101B
CL_DEVICE_GLOBAL_MEM_CACHE_TYPE = 0x101C
CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE = 0x101D
CL_DEVICE_GLOBAL_MEM_CACHE_SIZE = 0x101E
CL_DEVICE_GLOBAL_MEM_SIZE = 0x101F
CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE = 0x1020
CL_DEVICE_MAX_CONSTANT_ARGS = 0x1021
CL_DEVICE_LOCAL_MEM_TYPE = 0x1022
CL_DEVICE_LOCAL_MEM_SIZE = 0x1023
CL_DEVICE_ERROR_CORRECTION_SUPPORT = 0x1024
CL_DEVICE_PROFILING_TIMER_RESOLUTION = 0x1025
CL_DEVICE_ENDIAN_LITTLE = 0x1026
CL_DEVICE_AVAILABLE = 0x1027
CL_DEVICE_COMPILER_AVAILABLE = 0x1028
CL_DEVICE_EXECUTION_CAPABILITIES = 0x1029
CL_DEVICE_QUEUE_PROPERTIES = 0x102A
CL_DEVICE_NAME = 0x102B
CL_DEVICE_VENDOR = 0x102C
CL_DRIVER_VERSION = 0x102D
CL_DEVICE_PROFILE = 0x102E
CL_DEVICE_VERSION = 0x102F
CL_DEVICE_EXTENSIONS = 0x1030
CL_DEVICE_PLATFORM = 0x1031
CL_DEVICE_DOUBLE_FP_CONFIG = 0x1032
CL_DEVICE_HALF_FP_CONFIG = 0x1033
CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF = 0x1034
CL_DEVICE_HOST_UNIFIED_MEMORY = 0x1035
CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR = 0x1036
CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT = 0x1037
CL_DEVICE_NATIVE_VECTOR_WIDTH_INT = 0x1038
CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG = 0x1039
CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT = 0x103A
CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE = 0x103B
CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF = 0x103C
CL_DEVICE_OPENCL_C_VERSION = 0x103D
CL_DEVICE_LINKER_AVAILABLE = 0x103E
CL_DEVICE_BUILT_IN_KERNELS = 0x103F
CL_DEVICE_IMAGE_MAX_BUFFER_SIZE = 0x1040
CL_DEVICE_IMAGE_MAX_ARRAY_SIZE = 0x1041
CL_DEVICE_PARENT_DEVICE = 0x1042
CL_DEVICE_PARTITION_MAX_SUB_DEVICES = 0x1043
CL_DEVICE_PARTITION_PROPERTIES = 0x1044
CL_DEVICE_PARTITION_AFFINITY_DOMAIN = 0x1045
CL_DEVICE_PARTITION_TYPE = 0x1046
CL_DEVICE_REFERENCE_COUNT = 0x1047
CL_DEVICE_PREFERRED_INTEROP_USER_SYNC = 0x1048
CL_DEVICE_PRINTF_BUFFER_SIZE = 0x1049
CL_DEVICE_IMAGE_PITCH_ALIGNMENT = 0x104A
CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT = 0x104B
class cl_device_fp_config(cl_bitfield):
"""
One of the possible return types from :func:`clGetDeviceInfo`.
Bitfield identifying the floating point capabilities of the device.
"""
CL_FP_DENORM = (1 << 0)
CL_FP_INF_NAN = (1 << 1)
CL_FP_ROUND_TO_NEAREST = (1 << 2)
CL_FP_ROUND_TO_ZERO = (1 << 3)
CL_FP_ROUND_TO_INF = (1 << 4)
CL_FP_FMA = (1 << 5)
CL_FP_SOFT_FLOAT = (1 << 6)
class cl_device_mem_cache_type(cl_uenum):
"""
One of the possible return types from :func:`clGetDeviceInfo`.
Describes the nature of the device's cache, if any.
"""
CL_NONE = 0x0
CL_READ_ONLY_CACHE = 0x1
CL_READ_WRITE_CACHE = 0x2
class cl_device_local_mem_type(cl_uenum):
"""
One of the possible return types from :func:`clGetDeviceInfo`.
Describes where 'local' memory lives in the device.
Presumably, :const:`~cl_device_local_mem_type.CL_GLOBAL` means
the device's local memory lives in the same address space as its
global memory.
"""
CL_LOCAL = 0x1
CL_GLOBAL = 0x2
class cl_device_exec_capabilities(cl_bitfield):
"""
One of the possible return types from :func:`clGetDeviceInfo`.
Bitfield identifying what kind of kernels can be executed.
All devices can execute OpenCL C kernels, but some have their
own native kernel types as well.
"""
CL_EXEC_KERNEL = (1 << 0)
CL_EXEC_NATIVE_KERNEL = (1 << 1)
class cl_device_partition_property(cl_bitfield):
CL_DEVICE_PARTITION_BY_COUNTS_LIST_END = 0x0
CL_DEVICE_PARTITION_EQUALLY = 0x1086
CL_DEVICE_PARTITION_BY_COUNTS = 0x1087
CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN = 0x1088
class cl_device_affinity_domain(cl_bitfield):
CL_DEVICE_AFFINITY_DOMAIN_NUMA = (1 << 0)
CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE = (1 << 1)
CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE = (1 << 2)
CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE = (1 << 3)
CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE = (1 << 4)
CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE = (1 << 5)
class cl_command_queue_properties(cl_bitfield):
"""
Bitfield representing the properties of a command queue.
"""
CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE = (1 << 0)
CL_QUEUE_PROFILING_ENABLE = (1 << 1)
class cl_context_properties(void_p):
"""
If you find yourself looking at an array of these and
need to make any sense of them... good luck! It's a list
of key-value pairs, null-terminated. The keys are unsigned ints
representing enum constants.
:const:`~cl_context_info.CL_CONTEXT_PLATFORM` (0x1084)
is the most common one you'll see. I believe the rest are
parts of extensions, such as the OpenGL interop extension.
The meaning of the odd elements depends entirely on the
enum that came just before it. In the case of
:const:`~cl_context_info.CL_CONTEXT_PLATFORM`,
the value represents a pointer to a cl_platform object.
"""
pass
class cl_context_info(cl_uenum):
"""
Parameter names understood by :func:`clGetContextInfo`.
Note that :const:`cl_context_inf.CL_CONTEXT_PLATFORM` does not technically
belong here, and the C-level code won't accept it. The wrapped
version of :func:`clGetContextInfo` will, however, recognize it
and extract the appropriate value from the context's
properties list.
"""
CL_CONTEXT_REFERENCE_COUNT = 0x1080
CL_CONTEXT_DEVICES = 0x1081
CL_CONTEXT_PROPERTIES = 0x1082
CL_CONTEXT_NUM_DEVICES = 0x1083
CL_CONTEXT_PLATFORM = 0x1084
# FIXME: right place for these?
CL_GL_CONTEXT_KHR = 0x2008
CL_EGL_DISPLAY_KHR = 0x2009
CL_GLX_DISPLAY_KHR = 0x200A
CL_WGL_HDC_KHR = 0x200B
CL_CGL_SHAREGROUP_KHR = 0x200C
CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE = 0x10000000
class cl_command_queue_info(cl_uenum):
"""
Parameter names understood by :func:`clGetCommandQueueInfo`
"""
CL_QUEUE_CONTEXT = 0x1090
CL_QUEUE_DEVICE = 0x1091
CL_QUEUE_REFERENCE_COUNT = 0x1092
CL_QUEUE_PROPERTIES = 0x1093
class cl_channel_order(cl_uenum):
"""
Indicates the meanings of vector fields in an image.
"""
CL_R = 0x10B0
CL_A = 0x10B1
CL_RG = 0x10B2
CL_RA = 0x10B3
CL_RGB = 0x10B4
CL_RGBA = 0x10B5
CL_BGRA = 0x10B6
CL_ARGB = 0x10B7
CL_INTENSITY = 0x10B8
CL_LUMINANCE = 0x10B9
CL_Rx = 0x10BA
CL_RGx = 0x10BB
CL_RGBx = 0x10BC
class cl_channel_type(cl_uenum):
"""
Indicates the type and size of image channels.
"""
CL_SNORM_INT8 = 0x10D0
CL_SNORM_INT16 = 0x10D1
CL_UNORM_INT8 = 0x10D2
CL_UNORM_INT16 = 0x10D3
CL_UNORM_SHORT_565 = 0x10D4
CL_UNORM_SHORT_555 = 0x10D5
CL_UNORM_INT_101010 = 0x10D6
CL_SIGNED_INT8 = 0x10D7
CL_SIGNED_INT16 = 0x10D8
CL_SIGNED_INT32 = 0x10D9
CL_UNSIGNED_INT8 = 0x10DA
CL_UNSIGNED_INT16 = 0x10DB
CL_UNSIGNED_INT32 = 0x10DC
CL_HALF_FLOAT = 0x10DD
CL_FLOAT = 0x10DE
class cl_mem_flags(cl_bitfield):
"""
Bitfield used when constructing a memory object.
Indicates both the read/write status of the memory as
well as how the memory interacts with whatever host
pointer was provided. See the OpenCL docs_ for
:func:`clCreateBuffer` for more information.
.. _docs: http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateBuffer.html
"""
CL_MEM_READ_WRITE = (1 << 0)
CL_MEM_WRITE_ONLY = (1 << 1)
CL_MEM_READ_ONLY = (1 << 2)
CL_MEM_USE_HOST_PTR = (1 << 3)
CL_MEM_ALLOC_HOST_PTR = (1 << 4)
CL_MEM_COPY_HOST_PTR = (1 << 5)
class cl_mem_object_type(cl_uenum):
"""
Possible return type for :func:`clGetMemObjectInfo`.
Indicates the type of the memory object.
"""
CL_MEM_OBJECT_BUFFER = 0x10F0
CL_MEM_OBJECT_IMAGE2D = 0x10F1
CL_MEM_OBJECT_IMAGE3D = 0x10F2
class cl_mem_info(cl_uenum):
"""
Parameter names accepted by :func:`clGetMemObjectInfo`
"""
CL_MEM_TYPE = 0x1100
CL_MEM_FLAGS = 0x1101
CL_MEM_SIZE = 0x1102
CL_MEM_HOST_PTR = 0x1103
CL_MEM_MAP_COUNT = 0x1104
CL_MEM_REFERENCE_COUNT = 0x1105
CL_MEM_CONTEXT = 0x1106
CL_MEM_ASSOCIATED_MEMOBJECT = 0x1107
CL_MEM_OFFSET = 0x1108
class cl_mem_migration_flags(cl_uenum):
"""
The set of possible parameter names used
with the :func:`clEnqueueMigrateMemObjects` function.
"""
CL_MIGRATE_MEM_OBJECT_HOST = 0x1
CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED = 0x2
class cl_image_info(cl_uenum):
"""
Parameter names accepted by :func:`clGetImageInfo`
"""
CL_IMAGE_FORMAT = 0x1110
CL_IMAGE_ELEMENT_SIZE = 0x1111
CL_IMAGE_ROW_PITCH = 0x1112
CL_IMAGE_SLICE_PITCH = 0x1113
CL_IMAGE_WIDTH = 0x1114
CL_IMAGE_HEIGHT = 0x1115
CL_IMAGE_DEPTH = 0x1116
class cl_buffer_create_type(cl_uenum):
"""
Parameter type for :func:`clCreateSubBuffer` that indicates
how the subbuffer will be described.
The only supported value is
:const:`~cl_buffer_create_type.CL_BUFFER_CREATE_TYPE_REGION`,
which indicates the subbuffer will be a contiguous region as
defined by a :class:`cl_buffer_region` struct.
"""
CL_BUFFER_CREATE_TYPE_REGION = 0x1220
class cl_addressing_mode(cl_uenum):
"""
Addressing mode for sampler objects.
Returned by :func:`clGetSamplerInfo`.
"""
CL_ADDRESS_NONE = 0x1130
CL_ADDRESS_CLAMP_TO_EDGE = 0x1131
CL_ADDRESS_CLAMP = 0x1132
CL_ADDRESS_REPEAT = 0x1133
CL_ADDRESS_MIRRORED_REPEAT = 0x1134
class cl_filter_mode(cl_uenum):
"""
Filter mode for sampler objects.
Returned by :func:`clGetSamplerInfo`.
"""
CL_FILTER_NEAREST = 0x1140
CL_FILTER_LINEAR = 0x1141
class cl_sampler_info(cl_uenum):
"""
Parameter names for :func:`clGetSamplerInfo`.
"""
CL_SAMPLER_REFERENCE_COUNT = 0x1150
CL_SAMPLER_CONTEXT = 0x1151
CL_SAMPLER_NORMALIZED_COORDS = 0x1152
CL_SAMPLER_ADDRESSING_MODE = 0x1153
CL_SAMPLER_FILTER_MODE = 0x1154
class cl_map_flags(cl_bitfield):
"""
Read/write flags used for applying memory mappings
to memory objects. See :func:`clEnqueueMapBuffer`
and :func:`clEnqueueMapImage`.
"""
CL_MAP_READ = (1 << 0)
CL_MAP_WRITE = (1 << 1)
class cl_program_info(cl_uenum):
"""
Parameter names for :func:`clGetProgramInfo`
"""
CL_PROGRAM_REFERENCE_COUNT = 0x1160
CL_PROGRAM_CONTEXT = 0x1161
CL_PROGRAM_NUM_DEVICES = 0x1162
CL_PROGRAM_DEVICES = 0x1163
CL_PROGRAM_SOURCE = 0x1164
CL_PROGRAM_BINARY_SIZES = 0x1165
CL_PROGRAM_BINARIES = 0x1166
class cl_program_build_info(cl_uenum):
"""
Parameter names for :func:`clGetProgramBuildInfo`
"""
CL_PROGRAM_BUILD_STATUS = 0x1181
CL_PROGRAM_BUILD_OPTIONS = 0x1182
CL_PROGRAM_BUILD_LOG = 0x1183
class cl_build_status(cl_enum):
"""
Returned by :func:`clGetProgramBuildInfo`.
Indicates build status for the program on the
specified device.
"""
CL_BUILD_SUCCESS = 0
CL_BUILD_NONE = -1
CL_BUILD_ERROR = -2
CL_BUILD_IN_PROGRESS = -3
class cl_kernel_info(cl_uenum):
"""
Parameter names for :func:`clGetKernelInfo`
"""
CL_KERNEL_FUNCTION_NAME = 0x1190
CL_KERNEL_NUM_ARGS = 0x1191
CL_KERNEL_REFERENCE_COUNT = 0x1192
CL_KERNEL_CONTEXT = 0x1193
CL_KERNEL_PROGRAM = 0x1194
class cl_kernel_work_group_info(cl_uenum):
"""
Parameter names for :func:`clGetKernelWorkGroupInfo`
"""
CL_KERNEL_WORK_GROUP_SIZE = 0x11B0
CL_KERNEL_COMPILE_WORK_GROUP_SIZE = 0x11B1
CL_KERNEL_LOCAL_MEM_SIZE = 0x11B2
CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE= 0x11B3
CL_KERNEL_PRIVATE_MEM_SIZE = 0x11B4
class cl_event_info(cl_uenum):
"""
Parameter names for :func:`clGetEventInfo`
"""
CL_EVENT_COMMAND_QUEUE = 0x11D0
CL_EVENT_COMMAND_TYPE = 0x11D1
CL_EVENT_REFERENCE_COUNT = 0x11D2
CL_EVENT_COMMAND_EXECUTION_STATUS = 0x11D3
CL_EVENT_CONTEXT = 0x11D4
class cl_command_type(cl_uenum):
"""
Command types recorded on events and returned by
:func:`clGetEventInfo`.
"""
CL_COMMAND_NDRANGE_KERNEL = 0x11F0
CL_COMMAND_TASK = 0x11F1
CL_COMMAND_NATIVE_KERNEL = 0x11F2
CL_COMMAND_READ_BUFFER = 0x11F3
CL_COMMAND_WRITE_BUFFER = 0x11F4
CL_COMMAND_COPY_BUFFER = 0x11F5
CL_COMMAND_READ_IMAGE = 0x11F6
CL_COMMAND_WRITE_IMAGE = 0x11F7
CL_COMMAND_COPY_IMAGE = 0x11F8
CL_COMMAND_COPY_IMAGE_TO_BUFFER = 0x11F9
CL_COMMAND_COPY_BUFFER_TO_IMAGE = 0x11FA
CL_COMMAND_MAP_BUFFER = 0x11FB
CL_COMMAND_MAP_IMAGE = 0x11FC
CL_COMMAND_UNMAP_MEM_OBJECT = 0x11FD
CL_COMMAND_MARKER = 0x11FE
CL_COMMAND_ACQUIRE_GL_OBJECTS = 0x11FF
CL_COMMAND_RELEASE_GL_OBJECTS = 0x1200
CL_COMMAND_READ_BUFFER_RECT = 0x1201
CL_COMMAND_WRITE_BUFFER_RECT = 0x1202
CL_COMMAND_COPY_BUFFER_RECT = 0x1203
CL_COMMAND_USER = 0x1204
class cl_command_execution_status(cl_uenum):
"""
Status of the command associated with an event,
returned by :func:`clGetEventInfo`.
"""
CL_COMPLETE = 0x0
CL_RUNNING = 0x1
CL_SUBMITTED = 0x2
CL_QUEUED = 0x3
class cl_profiling_info(cl_uenum):
"""
Parameter names for :func:`clGetEventProfilingInfo`.
Indicates the point in time of the event's life that
should be queried.
"""
CL_PROFILING_COMMAND_QUEUED = 0x1280
CL_PROFILING_COMMAND_SUBMIT = 0x1281
CL_PROFILING_COMMAND_START = 0x1282
CL_PROFILING_COMMAND_END = 0x1283
class cl_image_format(ctypes.Structure):
"""
Represents image formats. See :func:`clCreateImage2D`.
.. attribute:: image_channel_order
A :class:`cl_channel_order` value
.. attribute:: image_channel_data_type
A :class:`cl_channel_type` value
"""
_fields_ = [('image_channel_order', cl_channel_order),
('image_channel_data_type', cl_channel_type),]
def __repr__(self):
return "%s(%s, %s)" % (self.__class__.__name__,
self.image_channel_order,
self.image_channel_data_type)
class cl_buffer_region(ctypes.Structure):
"""
A buffer region has two fields: :attr:`origin` and :attr:`size`.
Both are of type :c:type:`size_t`.
See :func:`clCreateSubBuffer` for usage.
"""
_fields_ = [('origin', size_t),
('size', size_t),]
def __repr__(self):
return "%s(%s, %s)" % (self.__class__.__name__,
int(self.origin),
int(self.size))
# Take care of some last-minute meta stuff.
# I would use metaclasses to handle this, but Python 3 expects different
# metaclass syntax, and I didn't want to have to run it through 2to3.
# I would use class decorators to handle this, but Python 2.5 doesn't
# understand them. And it's easier to iterate through like this than to
# write in the "manual class decorator" line after each class.
# For enums and bitfields, do magic. Each type gets a registry of the
# names and values of their defined elements, to support pretty printing.
# Further, each of the class variables (which are defined using ints) is
# upgraded to be a member of the class in question.
# Additionally, each of the constants is copied into the module scope.
for cls in (cl_enum.__subclasses__() +
cl_uenum.__subclasses__() +
cl_bitfield.__subclasses__()):
if cls.__name__ not in globals():
# Don't apply this to types that ctypes makes automatically,
# like the _be classes. Doing so will overwrite the declared
# constants at global scope, which is really weird.
continue
cls._by_name = dict()
cls._by_value = dict()
if not cls.__doc__:
cls.__doc__ = ""
for name, value in cls.__dict__.items():
if isinstance(value, int):
obj = cls(value)
setattr(cls, name, obj)
cls._by_name[name] = obj
cls._by_value[obj] = name
globals()[name] = obj
cls.__doc__ += """
.. attribute:: %s
""" % name
cls.NONE = cls(0)
# cleanup
del cls; del name; del value; del obj
# Generate exception tree
class OpenCLError(Exception):
"""
The base class from which all of the (generated)
OpenCL errors are descended. These exceptions
correspond to the :class:`cl_errnum` status codes.
"""
pass
cl_errnum._errors = dict()
for name, val in cl_errnum._by_name.items():
if name == "CL_SUCCESS": continue # Sorry, no SuccessError
errname = "".join(y.title() for y in name.split("_")[1:]) + 'Error'
errtype = type(errname, (OpenCLError,), {'value':val})
globals()[errname] = errtype
cl_errnum._errors[val] = errtype
del name; del val; del errname; del errtype
# Locate and load the shared library.
_dll_filename = os.getenv('PYCL_OPENCL')
if not _dll_filename:
try:
from ctypes.util import find_library as _find_library
_dll_filename = _find_library('OpenCL')
except ImportError:
pass
if _dll_filename:
try:
_dll = ctypes.cdll.LoadLibrary(_dll_filename)
except:
raise RuntimeError('Could not load OpenCL dll: %s' % _dll_filename)
else:
if os.environ.get('READTHEDOCS', None) == 'True':
# Don't care if we can load the DLL on RTD.
_dll = None
else:
raise RuntimeError(
'Could not locate OpenCL dll. Please set the PYCL_OPENCL environment variable to its full path.')
def _result_errcheck(result, func, args):
"""
For use in the errcheck attribute of a ctypes function wrapper.
Most OpenCL functions return a cl_errnum. This checks it for
an error code and raises an appropriate exception if it finds one.
This is the default error checker when using _wrapdll
"""
if result != cl_errnum.CL_SUCCESS:
raise cl_errnum._errors[result]
return result
def _lastarg_errcheck(result, func, args):
"""
For use in the errcheck attribute of a ctypes function wrapper.
Most OpenCL functions that don't return their error code expect
you to provide a pointer for it as the last argument. To use this,
the last argument of the call should be something like `byref(cl_errnum())`
"""
lastarg = args[-1]
if hasattr(lastarg, '_obj'):
status = lastarg._obj
else:
# In PyPy, the byref object is an actual pointer.
status = lastarg[0]
if status != cl_errnum.CL_SUCCESS:
raise cl_errnum._errors[status]
return result
def _wrapdll(*argtypes, **kw):
"""
Decorator used to simplify wrapping OpenCL functions a bit.
The positional arguments represent the ctypes argument types the
C-level function expects, and will be used to do argument type checking.
If a `res` keyword argument is given, it represents the C-level
function's expected return type. The default is `cl_errnum`.
If an `err` keyword argument is given, it represents an error checker
that should be run after low-level calls. The `_result_errcheck` and
`_lastarg_errcheck` functions should be sufficient for most OpenCL
functions. `_result_errcheck` is the default value.
The decorated function should have the same name as the underlying
OpenCL function, since the function name is used to do the lookup. The
C-level function pointer will be stored in the decorated function's
`call` attribute, and should be used by the decorated function to
perform the actual call(s). The wrapped function is otherwise untouched.
If no C-level function by this name is found in the OpenCL library
(perhaps it's version 1.0?) the decorator will discard the original
function. The replacement simply raises NotImplementedError if called.
.. todo::
Reconsider this last bit. Maybe let the wrapper compensate for the
lack of function pointer.
"""
def dowrap(f):
try:
wrapped_func = getattr(_dll, f.__name__)
except:
def badfunc(*args, **kw):
raise NotImplementedError("Function %s not present "
"in this version of OpenCL" %
f.__name__)
wrapped_func = badfunc
wrapped_func.argtypes = argtypes
res = kw.pop('res', cl_errnum)
wrapped_func.restype = res
err = kw.pop('err', _result_errcheck)
wrapped_func.errcheck = err
f.call = wrapped_func
return f
return dowrap
#################
# Event Objects #
#################
class cl_event(void_p):
"""
An OpenCL Event object. Returned by functions that add commands
to a :class:`cl_command_queue`, and often accepted (singly or in
lists) by the ``wait_for`` argument of these functions to impose
ordering.
Use :meth:`wait` to wait for a particular event to complete, or
:func:`clWaitForEvents` to wait for several of them at once.
These objects participate in OpenCL's reference counting scheme.
"""
@property
def queue(self):
"""The queue this event was emitted from."""
try: return self._queue
except AttributeError:
return clGetEventInfo(self, cl_event_info.CL_EVENT_COMMAND_QUEUE)
@property
def context(self):
"""The context this event exists within."""
try: return self._context
except AttributeError: