pyopencl 2025.1__cp312-cp312-macosx_10_14_x86_64.whl → 2025.2.2__cp312-cp312-macosx_10_14_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyopencl might be problematic. Click here for more details.

pyopencl/__init__.py CHANGED
@@ -23,27 +23,30 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  THE SOFTWARE.
24
24
  """
25
25
 
26
+ from typing_extensions import override
27
+ from dataclasses import dataclass
26
28
  import logging
27
- from sys import intern
28
- from typing import Any, Sequence
29
+ from typing import (
30
+ TYPE_CHECKING, Any, Generic, Literal, TypeAlias, TypeVar, cast,
31
+ overload)
32
+ from collections.abc import Callable
33
+ from collections.abc import Sequence
29
34
  from warnings import warn
30
35
 
31
36
  # must import, otherwise dtype registry will not be fully populated
32
37
  import pyopencl.cltypes
33
- from pyopencl.version import VERSION, VERSION_STATUS, VERSION_TEXT # noqa: F401
38
+ from pyopencl.version import VERSION, VERSION_STATUS, VERSION_TEXT
34
39
 
35
40
 
36
41
  __version__ = VERSION_TEXT
37
42
 
38
43
  logger = logging.getLogger(__name__)
39
44
 
40
- # This supports ocl-icd find shipped OpenCL ICDs, cf.
45
+ # This tells ocl-icd where to find shipped OpenCL ICDs, cf.
41
46
  # https://github.com/isuruf/ocl-icd/commit/3862386b51930f95d9ad1089f7157a98165d5a6b
42
47
  # via
43
48
  # https://github.com/inducer/pyopencl/blob/0b3d0ef92497e6838eea300b974f385f94cb5100/scripts/build-wheels.sh#L43-L44
44
49
  import os
45
-
46
-
47
50
  os.environ["PYOPENCL_HOME"] = os.path.dirname(os.path.abspath(__file__))
48
51
 
49
52
  try:
@@ -63,6 +66,12 @@ import sys
63
66
 
64
67
  _PYPY = "__pypy__" in sys.builtin_module_names
65
68
 
69
+ from pyopencl.typing import (
70
+ DTypeT,
71
+ HasBufferInterface,
72
+ SVMInnerT,
73
+ WaitList,
74
+ )
66
75
  from pyopencl._cl import ( # noqa: F401
67
76
  get_cl_header_version,
68
77
  program_kind,
@@ -176,69 +185,64 @@ from pyopencl._cl import ( # noqa: F401
176
185
  )
177
186
 
178
187
 
179
- try:
180
- from pyopencl._cl import DeviceTopologyAmd # noqa: F401
181
- from pyopencl._cl import enqueue_copy_buffer_p2p_amd # noqa: F401
182
- except ImportError:
183
- pass
188
+ if TYPE_CHECKING:
189
+ from numpy.typing import NDArray
190
+ from pyopencl._cl import (
191
+ DeviceTopologyAmd,
192
+ enqueue_copy_buffer_p2p_amd,
193
+ enqueue_map_buffer,
194
+ enqueue_map_image,
195
+ UserEvent, ImageDescriptor,
196
+ SVM, SVMAllocation, SVMPointer,
197
+ # _enqueue_barrier_with_wait_list, _enqueue_fill_buffer,
198
+ # _enqueue_marker_with_wait_list,
199
+ enqueue_fill_image,
200
+ enqueue_migrate_mem_objects, unload_platform_compiler,
201
+ GLBuffer, GLRenderBuffer, GLTexture, gl_object_type, gl_texture_info,
202
+ get_apple_cgl_share_group,
203
+ enqueue_acquire_gl_objects,
204
+ enqueue_release_gl_objects,
205
+ )
206
+ else:
207
+ try:
208
+ from pyopencl._cl import DeviceTopologyAmd
209
+ from pyopencl._cl import enqueue_copy_buffer_p2p_amd
210
+ except ImportError:
211
+ pass
184
212
 
185
- if not _PYPY:
186
- # FIXME: Add back to default set when pypy support catches up
187
- from pyopencl._cl import enqueue_map_buffer # noqa: F401
188
- from pyopencl._cl import enqueue_map_image # noqa: F401
213
+ if not _PYPY:
214
+ # FIXME: Add back to default set when pypy support catches up
215
+ from pyopencl._cl import enqueue_map_buffer
216
+ from pyopencl._cl import enqueue_map_image
189
217
 
190
- if get_cl_header_version() >= (1, 1):
191
- from pyopencl._cl import UserEvent # noqa: F401
192
- if get_cl_header_version() >= (1, 2):
193
- from pyopencl._cl import ImageDescriptor
194
- from pyopencl._cl import ( # noqa: F401
195
- _enqueue_barrier_with_wait_list, _enqueue_fill_buffer,
196
- _enqueue_marker_with_wait_list, enqueue_fill_image,
197
- enqueue_migrate_mem_objects, unload_platform_compiler)
218
+ if get_cl_header_version() >= (1, 1):
219
+ from pyopencl._cl import UserEvent
220
+ if get_cl_header_version() >= (1, 2):
221
+ from pyopencl._cl import ImageDescriptor
222
+ from pyopencl._cl import ( # noqa: F401
223
+ _enqueue_barrier_with_wait_list, _enqueue_fill_buffer,
224
+ _enqueue_marker_with_wait_list, enqueue_fill_image,
225
+ enqueue_migrate_mem_objects, unload_platform_compiler)
198
226
 
199
- if get_cl_header_version() >= (2, 0):
200
- from pyopencl._cl import SVM, SVMAllocation, SVMPointer
227
+ if get_cl_header_version() >= (2, 0):
228
+ from pyopencl._cl import SVM, SVMAllocation, SVMPointer
201
229
 
202
- if _cl.have_gl():
203
- from pyopencl._cl import ( # noqa: F401
204
- GLBuffer, GLRenderBuffer, GLTexture, gl_object_type, gl_texture_info)
230
+ if _cl.have_gl():
231
+ from pyopencl._cl import (
232
+ GLBuffer, GLRenderBuffer, GLTexture, gl_object_type, gl_texture_info)
205
233
 
206
- try:
207
- from pyopencl._cl import get_apple_cgl_share_group # noqa: F401
208
- except ImportError:
209
- pass
234
+ try:
235
+ from pyopencl._cl import get_apple_cgl_share_group
236
+ except ImportError:
237
+ pass
210
238
 
211
- try:
212
- from pyopencl._cl import enqueue_acquire_gl_objects # noqa: F401
213
- from pyopencl._cl import enqueue_release_gl_objects # noqa: F401
214
- except ImportError:
215
- pass
239
+ try:
240
+ from pyopencl._cl import enqueue_acquire_gl_objects
241
+ from pyopencl._cl import enqueue_release_gl_objects
242
+ except ImportError:
243
+ pass
216
244
 
217
- import inspect as _inspect
218
-
219
-
220
- CONSTANT_CLASSES = tuple(
221
- getattr(_cl, name) for name in dir(_cl)
222
- if _inspect.isclass(getattr(_cl, name))
223
- and name[0].islower() and name not in ["zip", "map", "range"])
224
-
225
- BITFIELD_CONSTANT_CLASSES = (
226
- _cl.device_type,
227
- _cl.device_fp_config,
228
- _cl.device_exec_capabilities,
229
- _cl.command_queue_properties,
230
- _cl.mem_flags,
231
- _cl.map_flags,
232
- _cl.kernel_arg_type_qualifier,
233
- _cl.device_affinity_domain,
234
- _cl.mem_migration_flags,
235
- _cl.device_svm_capabilities,
236
- _cl.queue_properties,
237
- _cl.svm_mem_flags,
238
- _cl.device_atomic_capabilities,
239
- _cl.device_device_enqueue_capabilities,
240
- _cl.version_bits,
241
- )
245
+ import pyopencl._monkeypatch
242
246
 
243
247
 
244
248
  # {{{ diagnostics
@@ -271,11 +275,7 @@ def _find_pyopencl_include_path() -> str:
271
275
  # Try to find the include path in the same directory as this file
272
276
  include_path = join(abspath(dirname(__file__)), "cl")
273
277
  if not exists(include_path):
274
- try:
275
- # NOTE: only available in Python >=3.9
276
- from importlib.resources import files
277
- except ImportError:
278
- from importlib_resources import files # type: ignore[no-redef]
278
+ from importlib.resources import files
279
279
 
280
280
  include_path = str(files("pyopencl") / "cl")
281
281
  if not exists(include_path):
@@ -293,7 +293,9 @@ def _find_pyopencl_include_path() -> str:
293
293
 
294
294
  # {{{ build option munging
295
295
 
296
- def _split_options_if_necessary(options):
296
+ def _split_options_if_necessary(
297
+ options: str | Sequence[str]
298
+ ) -> Sequence[str]:
297
299
  if isinstance(options, str):
298
300
  import shlex
299
301
 
@@ -302,8 +304,8 @@ def _split_options_if_necessary(options):
302
304
  return options
303
305
 
304
306
 
305
- def _find_include_path(options):
306
- def unquote(path):
307
+ def _find_include_path(options: Sequence[str]) -> list[str]:
308
+ def unquote(path: str):
307
309
  if path.startswith('"') and path.endswith('"'):
308
310
  return path[1:-1]
309
311
  else:
@@ -330,8 +332,8 @@ def _find_include_path(options):
330
332
  return include_path
331
333
 
332
334
 
333
- def _options_to_bytestring(options):
334
- def encode_if_necessary(s):
335
+ def _options_to_bytestring(options: Sequence[str | bytes]):
336
+ def encode_if_necessary(s: str | bytes) -> bytes:
335
337
  if isinstance(s, str):
336
338
  return s.encode("utf-8")
337
339
  else:
@@ -359,7 +361,7 @@ _PLAT_BUILD_OPTIONS: dict[str, list[str]] = {
359
361
  }
360
362
 
361
363
 
362
- def enable_debugging(platform_or_context):
364
+ def enable_debugging(platform_or_context: Platform | Context) -> None:
363
365
  """Enables debugging for all code subsequently compiled by
364
366
  PyOpenCL on the passed *platform*. Alternatively, a context
365
367
  may be passed.
@@ -379,16 +381,44 @@ def enable_debugging(platform_or_context):
379
381
  stacklevel=2)
380
382
 
381
383
 
384
+ class RepeatedKernelRetrieval(UserWarning):
385
+ pass
386
+
387
+
388
+ RetT = TypeVar("RetT")
389
+
390
+
382
391
  class Program:
392
+ _prg: _Program | None
393
+ _context: Context
394
+ _source: str | bytes
395
+ _build_duration_info: tuple[str, bool, float] | None
396
+
397
+ @overload
398
+ def __init__(self, arg1: _Program) -> None: ...
399
+
400
+ @overload
401
+ def __init__(self, arg1: Context, arg2: str | bytes) -> None: ...
402
+
403
+ @overload
404
+ def __init__(
405
+ self,
406
+ arg1: Context,
407
+ arg2: Sequence[Device],
408
+ arg3: Sequence[bytes]
409
+ ) -> None: ...
410
+
383
411
  def __init__(self, arg1, arg2=None, arg3=None):
412
+ self._knl_retrieval_count: dict[str, int] = {}
413
+
384
414
  if arg2 is None:
385
415
  # 1-argument form: program
386
- self._prg = arg1
387
- self._context = self._prg.get_info(program_info.CONTEXT)
416
+ self._prg = cast("_Program", arg1)
417
+ self._context = cast("Context", self._prg.get_info(program_info.CONTEXT))
388
418
 
389
419
  elif arg3 is None:
390
420
  # 2-argument form: context, source
391
- context, source = arg1, arg2
421
+ context, source = cast("tuple[Context, str | bytes]", (arg1, arg2))
392
422
 
393
423
  from pyopencl.tools import is_spirv
394
424
  if is_spirv(source):
@@ -402,13 +432,13 @@ class Program:
402
432
  self._prg = None
403
433
 
404
434
  else:
405
- context, device, binaries = arg1, arg2, arg3
435
+ context, devices, binaries = arg1, arg2, arg3
406
436
  self._context = context
407
- self._prg = _cl._Program(context, device, binaries)
437
+ self._prg = _cl._Program(context, devices, binaries)
408
438
 
409
439
  self._build_duration_info = None
410
440
 
411
- def _get_prg(self):
441
+ def _get_prg(self) -> _Program:
412
442
  if self._prg is not None:
413
443
  return self._prg
414
444
  else:
@@ -419,13 +449,13 @@ class Program:
419
449
  self._prg = _cl._Program(self._context, self._source)
420
450
  return self._prg
421
451
 
422
- def get_info(self, arg):
452
+ def get_info(self, arg: program_info) -> object:
423
453
  return self._get_prg().get_info(arg)
424
454
 
425
455
  def get_build_info(self, *args, **kwargs):
426
456
  return self._get_prg().get_build_info(*args, **kwargs)
427
457
 
428
- def all_kernels(self):
458
+ def all_kernels(self) -> Sequence[Kernel]:
429
459
  return self._get_prg().all_kernels()
430
460
 
431
461
  @property
@@ -434,17 +464,30 @@ class Program:
434
464
  int_ptr.__doc__ = _cl._Program.int_ptr.__doc__
435
465
 
436
466
  @staticmethod
437
- def from_int_ptr(int_ptr_value, retain=True):
467
+ def from_int_ptr(int_ptr_value: int, retain: bool = True):
438
468
  return Program(_cl._Program.from_int_ptr(int_ptr_value, retain))
439
469
  from_int_ptr.__doc__ = _cl._Program.from_int_ptr.__doc__
440
470
 
441
- def __getattr__(self, attr):
471
+ def __getattr__(self, attr: str) -> Kernel:
442
472
  try:
443
473
  knl = Kernel(self, attr)
444
474
  # Nvidia does not raise errors even for invalid names,
445
475
  # but this will give an error if the kernel is invalid.
446
476
  knl.num_args # noqa: B018
447
477
 
478
+ count = self._knl_retrieval_count[attr] = (
479
+ self._knl_retrieval_count.get(attr, 0) + 1)
480
+
481
+ if count == 2:
482
+ # https://github.com/inducer/pyopencl/issues/831
483
+ # https://github.com/inducer/pyopencl/issues/830#issuecomment-2913538384
484
+ warn(f"Kernel '{attr}' has been retrieved more than once. "
485
+ "Each retrieval creates a new, independent kernel, "
486
+ "at possibly considerable expense. "
487
+ "To avoid the expense, reuse the retrieved kernel instance. "
488
+ "To avoid this warning, use cl.Kernel(prg, name).",
489
+ RepeatedKernelRetrieval, stacklevel=2)
490
+
448
491
  if self._build_duration_info is not None:
449
492
  build_descr, _was_cached, duration = self._build_duration_info
450
493
  if duration > 0.2:
@@ -463,29 +506,37 @@ class Program:
463
506
  # {{{ build
464
507
 
465
508
  @classmethod
466
- def _process_build_options(cls, context, options, _add_include_path=False):
509
+ def _process_build_options(cls,
510
+ context: Context,
511
+ options: str | Sequence[str] | None,
512
+ _add_include_path: bool = False
513
+ ) -> tuple[bytes, Sequence[str]]:
467
514
  if options is None:
468
515
  options = []
469
- if isinstance(options, tuple):
470
- options = list(options)
471
516
 
472
517
  options = _split_options_if_necessary(options)
473
518
 
474
- options = (options
475
- + _DEFAULT_BUILD_OPTIONS
476
- + _DEFAULT_INCLUDE_OPTIONS
477
- + _PLAT_BUILD_OPTIONS.get(
478
- context.devices[0].platform.name, []))
519
+ options = (
520
+ *options,
521
+ *_DEFAULT_BUILD_OPTIONS,
522
+ *_DEFAULT_INCLUDE_OPTIONS,
523
+ *_PLAT_BUILD_OPTIONS.get(context.devices[0].platform.name, []))
479
524
 
480
525
  forced_options = os.environ.get("PYOPENCL_BUILD_OPTIONS")
481
526
  if forced_options:
482
- options = options + forced_options.split()
527
+ options = (
528
+ *options,
529
+ *forced_options.split())
483
530
 
484
531
  return (
485
532
  _options_to_bytestring(options),
486
533
  _find_include_path(options))
487
534
 
488
- def build(self, options=None, devices=None, cache_dir=None):
535
+ def build(self,
536
+ options: str | Sequence[str] | None = None,
537
+ devices: Sequence[Device] | None = None,
538
+ cache_dir: str | None = None,
539
+ ):
489
540
  options_bytes, include_path = self._process_build_options(
490
541
  self._context, options)
491
542
 
@@ -542,7 +593,11 @@ class Program:
542
593
 
543
594
  return self
544
595
 
545
- def _build_and_catch_errors(self, build_func, options_bytes, source=None):
596
+ def _build_and_catch_errors(self,
597
+ build_func: Callable[[], RetT],
598
+ options_bytes: bytes,
599
+ source: str | None = None,
600
+ ):
546
601
  try:
547
602
  return build_func()
548
603
  except RuntimeError as e:
@@ -575,7 +630,11 @@ class Program:
575
630
 
576
631
  # }}}
577
632
 
578
- def compile(self, options=None, devices=None, headers=None):
633
+ def compile(self,
634
+ options: str | Sequence[str] | None = None,
635
+ devices: Sequence[Device] | None = None,
636
+ headers: Sequence[tuple[str, Program]] | None = None
637
+ ):
579
638
  if headers is None:
580
639
  headers = []
581
640
 
@@ -585,15 +644,32 @@ class Program:
585
644
  [(name, prg._get_prg()) for name, prg in headers])
586
645
  return self
587
646
 
588
- def __eq__(self, other):
589
- return self._get_prg() == other._get_prg()
590
-
591
- def __ne__(self, other):
592
- return self._get_prg() == other._get_prg()
647
+ @override
648
+ def __eq__(self, other: object):
649
+ return (
650
+ isinstance(other, Program)
651
+ and self._get_prg() == other._get_prg())
593
652
 
653
+ @override
594
654
  def __hash__(self):
595
655
  return hash(self._get_prg())
596
656
 
657
+ reference_count: int # pyright: ignore[reportUninitializedInstanceVariable]
658
+ context: Context # pyright: ignore[reportUninitializedInstanceVariable]
659
+ num_devices: int # pyright: ignore[reportUninitializedInstanceVariable]
660
+ devices: Sequence[Device] # pyright: ignore[reportUninitializedInstanceVariable]
661
+ source: str # pyright: ignore[reportUninitializedInstanceVariable]
662
+ binary_sizes: int # pyright: ignore[reportUninitializedInstanceVariable]
663
+ binaries: Sequence[bytes] # pyright: ignore[reportUninitializedInstanceVariable]
664
+ num_kernels: int # pyright: ignore[reportUninitializedInstanceVariable]
665
+ kernel_names: str # pyright: ignore[reportUninitializedInstanceVariable]
666
+ il: bytes # pyright: ignore[reportUninitializedInstanceVariable]
667
+ scope_global_ctors_present: bool # pyright: ignore[reportUninitializedInstanceVariable]
668
+ scope_global_dtors_present: bool # pyright: ignore[reportUninitializedInstanceVariable]
669
+
670
+
671
+ pyopencl._monkeypatch.add_get_info(Program, Program.get_info, _cl.program_info)
672
+
597
673
 
598
674
  def create_program_with_built_in_kernels(context, devices, kernel_names):
599
675
  if not isinstance(kernel_names, str):
@@ -615,868 +691,6 @@ def link_program(context, programs, options=None, devices=None):
615
691
  # }}}
616
692
 
617
693
 
618
- # {{{ monkeypatch C++ wrappers to add functionality
619
-
620
- def _add_functionality():
621
- def generic_get_cl_version(self):
622
- import re
623
- version_string = self.version
624
- match = re.match(r"^OpenCL ([0-9]+)\.([0-9]+) .*$", version_string)
625
- if match is None:
626
- raise RuntimeError("%s %s returned non-conformant "
627
- "platform version string '%s'" %
628
- (type(self).__name__, self, version_string))
629
-
630
- return int(match.group(1)), int(match.group(2))
631
-
632
- # {{{ Platform
633
-
634
- def platform_repr(self):
635
- return f"<pyopencl.Platform '{self.name}' at 0x{self.int_ptr:x}>"
636
-
637
- Platform.__repr__ = platform_repr
638
- Platform._get_cl_version = generic_get_cl_version
639
-
640
- # }}}
641
-
642
- # {{{ Device
643
-
644
- def device_repr(self):
645
- return "<pyopencl.Device '{}' on '{}' at 0x{:x}>".format(
646
- self.name.strip(), self.platform.name.strip(), self.int_ptr)
647
-
648
- def device_hashable_model_and_version_identifier(self):
649
- return ("v1", self.vendor, self.vendor_id, self.name, self.version)
650
-
651
- def device_persistent_unique_id(self):
652
- warn("Device.persistent_unique_id is deprecated. "
653
- "Use Device.hashable_model_and_version_identifier instead.",
654
- DeprecationWarning, stacklevel=2)
655
- return device_hashable_model_and_version_identifier(self)
656
-
657
- Device.__repr__ = device_repr
658
-
659
- # undocumented for now:
660
- Device._get_cl_version = generic_get_cl_version
661
- Device.hashable_model_and_version_identifier = property(
662
- device_hashable_model_and_version_identifier)
663
- Device.persistent_unique_id = property(device_persistent_unique_id)
664
-
665
- # }}}
666
-
667
- # {{{ Context
668
-
669
- def context_repr(self):
670
- return "<pyopencl.Context at 0x{:x} on {}>".format(self.int_ptr,
671
- ", ".join(repr(dev) for dev in self.devices))
672
-
673
- def context_get_cl_version(self):
674
- return self.devices[0].platform._get_cl_version()
675
-
676
- Context.__repr__ = context_repr
677
- from pytools import memoize_method
678
- Context._get_cl_version = memoize_method(context_get_cl_version)
679
-
680
- # }}}
681
-
682
- # {{{ CommandQueue
683
-
684
- def command_queue_enter(self):
685
- return self
686
-
687
- def command_queue_exit(self, exc_type, exc_val, exc_tb):
688
- self.finish()
689
- self._finalize()
690
-
691
- def command_queue_get_cl_version(self):
692
- return self.device._get_cl_version()
693
-
694
- CommandQueue.__enter__ = command_queue_enter
695
- CommandQueue.__exit__ = command_queue_exit
696
- CommandQueue._get_cl_version = memoize_method(command_queue_get_cl_version)
697
-
698
- # }}}
699
-
700
- # {{{ _Program (the internal, non-caching version)
701
-
702
- def program_get_build_logs(self):
703
- build_logs = []
704
- for dev in self.get_info(_cl.program_info.DEVICES):
705
- try:
706
- log = self.get_build_info(dev, program_build_info.LOG)
707
- except Exception:
708
- log = "<error retrieving log>"
709
-
710
- build_logs.append((dev, log))
711
-
712
- return build_logs
713
-
714
- def program_build(self, options_bytes, devices=None):
715
- err = None
716
- try:
717
- self._build(options=options_bytes, devices=devices)
718
- except Error as e:
719
- msg = str(e) + "\n\n" + (75*"="+"\n").join(
720
- f"Build on {dev}:\n\n{log}"
721
- for dev, log in self._get_build_logs())
722
- code = e.code
723
- routine = e.routine
724
-
725
- err = _cl.RuntimeError(
726
- _cl._ErrorRecord(
727
- msg=msg,
728
- code=code,
729
- routine=routine))
730
-
731
- if err is not None:
732
- # Python 3.2 outputs the whole list of currently active exceptions
733
- # This serves to remove one (redundant) level from that nesting.
734
- raise err
735
-
736
- message = (75*"="+"\n").join(
737
- f"Build on {dev} succeeded, but said:\n\n{log}"
738
- for dev, log in self._get_build_logs()
739
- if log is not None and log.strip())
740
-
741
- if message:
742
- if self.kind() == program_kind.SOURCE:
743
- build_type = "From-source build"
744
- elif self.kind() == program_kind.BINARY:
745
- build_type = "From-binary build"
746
- elif self.kind() == program_kind.IL:
747
- build_type = "From-IL build"
748
- else:
749
- build_type = "Build"
750
-
751
- compiler_output("%s succeeded, but resulted in non-empty logs:\n%s"
752
- % (build_type, message))
753
-
754
- return self
755
-
756
- _cl._Program._get_build_logs = program_get_build_logs
757
- _cl._Program.build = program_build
758
-
759
- # }}}
760
-
761
- # {{{ Event
762
- class ProfilingInfoGetter:
763
- def __init__(self, event):
764
- self.event = event
765
-
766
- def __getattr__(self, name):
767
- info_cls = _cl.profiling_info
768
-
769
- try:
770
- inf_attr = getattr(info_cls, name.upper())
771
- except AttributeError as err:
772
- raise AttributeError("%s has no attribute '%s'"
773
- % (type(self), name)) from err
774
- else:
775
- return self.event.get_profiling_info(inf_attr)
776
-
777
- _cl.Event.profile = property(ProfilingInfoGetter)
778
-
779
- # }}}
780
-
781
- # {{{ Kernel
782
-
783
- kernel_old_get_info = Kernel.get_info
784
- kernel_old_get_work_group_info = Kernel.get_work_group_info
785
-
786
- def kernel_set_arg_types(self, arg_types):
787
- arg_types = tuple(arg_types)
788
-
789
- # {{{ arg counting bug handling
790
-
791
- # For example:
792
- # https://github.com/pocl/pocl/issues/197
793
- # (but Apple CPU has a similar bug)
794
-
795
- work_around_arg_count_bug = False
796
- warn_about_arg_count_bug = False
797
-
798
- from pyopencl.characterize import has_struct_arg_count_bug
799
-
800
- count_bug_per_dev = [
801
- has_struct_arg_count_bug(dev, self.context)
802
- for dev in self.context.devices]
803
-
804
- from pytools import single_valued
805
- if any(count_bug_per_dev):
806
- if all(count_bug_per_dev):
807
- work_around_arg_count_bug = single_valued(count_bug_per_dev)
808
- else:
809
- warn_about_arg_count_bug = True
810
-
811
- # }}}
812
-
813
- from pyopencl.invoker import generate_enqueue_and_set_args
814
- self._set_enqueue_and_set_args(
815
- *generate_enqueue_and_set_args(
816
- self.function_name,
817
- len(arg_types), self.num_args,
818
- arg_types,
819
- warn_about_arg_count_bug=warn_about_arg_count_bug,
820
- work_around_arg_count_bug=work_around_arg_count_bug,
821
- devs=self.context.devices))
822
-
823
- def kernel_get_work_group_info(self, param, device):
824
- try:
825
- wg_info_cache = self._wg_info_cache
826
- except AttributeError:
827
- wg_info_cache = self._wg_info_cache = {}
828
-
829
- cache_key = (param, device.int_ptr)
830
- try:
831
- return wg_info_cache[cache_key]
832
- except KeyError:
833
- pass
834
-
835
- result = kernel_old_get_work_group_info(self, param, device)
836
- wg_info_cache[cache_key] = result
837
- return result
838
-
839
- def kernel_capture_call(self, output_file, queue, global_size, local_size,
840
- *args, **kwargs):
841
- from pyopencl.capture_call import capture_kernel_call
842
- capture_kernel_call(self, output_file, queue, global_size, local_size,
843
- *args, **kwargs)
844
-
845
- def kernel_get_info(self, param_name):
846
- val = kernel_old_get_info(self, param_name)
847
-
848
- if isinstance(val, _Program):
849
- return Program(val)
850
- else:
851
- return val
852
-
853
- Kernel.get_work_group_info = kernel_get_work_group_info
854
-
855
- # FIXME: Possibly deprecate this version
856
- Kernel.set_scalar_arg_dtypes = kernel_set_arg_types
857
- Kernel.set_arg_types = kernel_set_arg_types
858
-
859
- Kernel.capture_call = kernel_capture_call
860
- Kernel.get_info = kernel_get_info
861
-
862
- # }}}
863
-
864
- # {{{ ImageFormat
865
-
866
- def image_format_repr(self):
867
- return "ImageFormat({}, {})".format(
868
- channel_order.to_string(self.channel_order,
869
- "<unknown channel order 0x%x>"),
870
- channel_type.to_string(self.channel_data_type,
871
- "<unknown channel data type 0x%x>"))
872
-
873
- def image_format_eq(self, other):
874
- return (self.channel_order == other.channel_order
875
- and self.channel_data_type == other.channel_data_type)
876
-
877
- def image_format_ne(self, other):
878
- return not image_format_eq(self, other)
879
-
880
- def image_format_hash(self):
881
- return hash((type(self), self.channel_order, self.channel_data_type))
882
-
883
- ImageFormat.__repr__ = image_format_repr
884
- ImageFormat.__eq__ = image_format_eq
885
- ImageFormat.__ne__ = image_format_ne
886
- ImageFormat.__hash__ = image_format_hash
887
-
888
- # }}}
889
-
890
- # {{{ Image
891
-
892
- def image_init(
893
- self, context, flags, format, shape=None, pitches=None,
894
- hostbuf=None, is_array=False, buffer=None, *,
895
- desc: ImageDescriptor | None = None,
896
- _through_create_image: bool = False,
897
- ) -> None:
898
- if hostbuf is not None and not \
899
- (flags & (mem_flags.USE_HOST_PTR | mem_flags.COPY_HOST_PTR)):
900
- warn("'hostbuf' was passed, but no memory flags to make use of it.",
901
- stacklevel=2)
902
-
903
- if desc is not None:
904
- if shape is not None:
905
- raise TypeError("shape may not be passed when using descriptor")
906
- if pitches is not None:
907
- raise TypeError("pitches may not be passed when using descriptor")
908
- if is_array:
909
- raise TypeError("is_array may not be passed when using descriptor")
910
- if buffer is not None:
911
- raise TypeError("is_array may not be passed when using descriptor")
912
-
913
- Image._custom_init(self, context, flags, format, desc, hostbuf)
914
-
915
- return
916
-
917
- if shape is None and hostbuf is None:
918
- raise Error("'shape' must be passed if 'hostbuf' is not given")
919
-
920
- if shape is None and hostbuf is not None:
921
- shape = hostbuf.shape
922
-
923
- if hostbuf is None and pitches is not None:
924
- raise Error("'pitches' may only be given if 'hostbuf' is given")
925
-
926
- if context._get_cl_version() >= (1, 2) and get_cl_header_version() >= (1, 2):
927
- if not _through_create_image:
928
- warn("Non-descriptor Image constructor called. "
929
- "This will stop working in 2026. "
930
- "Use create_image instead (with the same arguments).",
931
- DeprecationWarning, stacklevel=2)
932
-
933
- if buffer is not None and is_array:
934
- raise ValueError(
935
- "'buffer' and 'is_array' are mutually exclusive")
936
-
937
- if len(shape) == 3:
938
- if buffer is not None:
939
- raise TypeError(
940
- "'buffer' argument is not supported for 3D arrays")
941
- elif is_array:
942
- image_type = mem_object_type.IMAGE2D_ARRAY
943
- else:
944
- image_type = mem_object_type.IMAGE3D
945
-
946
- elif len(shape) == 2:
947
- if buffer is not None:
948
- raise TypeError(
949
- "'buffer' argument is not supported for 2D arrays")
950
- elif is_array:
951
- image_type = mem_object_type.IMAGE1D_ARRAY
952
- else:
953
- image_type = mem_object_type.IMAGE2D
954
-
955
- elif len(shape) == 1:
956
- if buffer is not None:
957
- image_type = mem_object_type.IMAGE1D_BUFFER
958
- elif is_array:
959
- raise TypeError("array of zero-dimensional images not supported")
960
- else:
961
- image_type = mem_object_type.IMAGE1D
962
-
963
- else:
964
- raise ValueError("images cannot have more than three dimensions")
965
-
966
- desc = ImageDescriptor() \
967
- # pylint: disable=possibly-used-before-assignment
968
-
969
- desc.image_type = image_type
970
- desc.shape = shape # also sets desc.array_size
971
-
972
- if pitches is None:
973
- desc.pitches = (0, 0)
974
- else:
975
- desc.pitches = pitches
976
-
977
- desc.num_mip_levels = 0 # per CL 1.2 spec
978
- desc.num_samples = 0 # per CL 1.2 spec
979
- desc.buffer = buffer
980
-
981
- Image._custom_init(self, context, flags, format, desc, hostbuf)
982
- else:
983
- # legacy init for CL 1.1 and older
984
- if is_array:
985
- raise TypeError("'is_array=True' is not supported for CL < 1.2")
986
- # if num_mip_levels is not None:
987
- # raise TypeError(
988
- # "'num_mip_levels' argument is not supported for CL < 1.2")
989
- # if num_samples is not None:
990
- # raise TypeError(
991
- # "'num_samples' argument is not supported for CL < 1.2")
992
- if buffer is not None:
993
- raise TypeError("'buffer' argument is not supported for CL < 1.2")
994
-
995
- Image._custom_init(self, context, flags, format, shape,
996
- pitches, hostbuf)
997
-
998
- class _ImageInfoGetter:
999
- def __init__(self, event):
1000
- warn(
1001
- "Image.image.attr is deprecated and will go away in 2021. "
1002
- "Use Image.attr directly, instead.", stacklevel=2)
1003
-
1004
- self.event = event
1005
-
1006
- def __getattr__(self, name):
1007
- try:
1008
- inf_attr = getattr(_cl.image_info, name.upper())
1009
- except AttributeError as err:
1010
- raise AttributeError("%s has no attribute '%s'"
1011
- % (type(self), name)) from err
1012
- else:
1013
- return self.event.get_image_info(inf_attr)
1014
-
1015
- def image_shape(self):
1016
- if self.type == mem_object_type.IMAGE2D:
1017
- return (self.width, self.height)
1018
- elif self.type == mem_object_type.IMAGE3D:
1019
- return (self.width, self.height, self.depth)
1020
- else:
1021
- raise LogicError("only images have shapes")
1022
-
1023
- Image.__init__ = image_init
1024
- Image.image = property(_ImageInfoGetter)
1025
- Image.shape = property(image_shape)
1026
-
1027
- # }}}
1028
-
1029
- # {{{ Error
1030
-
1031
- def error_str(self):
1032
- val = self.what
1033
- try:
1034
- val.routine # noqa: B018
1035
- except AttributeError:
1036
- return str(val)
1037
- else:
1038
- result = ""
1039
- if val.code() != status_code.SUCCESS:
1040
- result = status_code.to_string(
1041
- val.code(), "<unknown error %d>")
1042
- routine = val.routine()
1043
- if routine:
1044
- result = f"{routine} failed: {result}"
1045
- what = val.what()
1046
- if what:
1047
- if result:
1048
- result += " - "
1049
- result += what
1050
- return result
1051
-
1052
- def error_code(self):
1053
- return self.args[0].code()
1054
-
1055
- def error_routine(self):
1056
- return self.args[0].routine()
1057
-
1058
- def error_what(self):
1059
- return self.args[0]
1060
-
1061
- Error.__str__ = error_str
1062
- Error.code = property(error_code)
1063
- Error.routine = property(error_routine)
1064
- Error.what = property(error_what)
1065
-
1066
- # }}}
1067
-
1068
- # {{{ MemoryMap
1069
-
1070
- def memory_map_enter(self):
1071
- return self
1072
-
1073
- def memory_map_exit(self, exc_type, exc_val, exc_tb):
1074
- self.release()
1075
-
1076
- MemoryMap.__doc__ = """
1077
- This class may also be used as a context manager in a ``with`` statement.
1078
- The memory corresponding to this object will be unmapped when
1079
- this object is deleted or :meth:`release` is called.
1080
-
1081
- .. automethod:: release
1082
- """
1083
- MemoryMap.__enter__ = memory_map_enter
1084
- MemoryMap.__exit__ = memory_map_exit
1085
-
1086
- # }}}
1087
-
1088
- # {{{ SVMPointer
1089
-
1090
- if get_cl_header_version() >= (2, 0):
1091
- SVMPointer.__doc__ = """A base class for things that can be passed to
1092
- functions that allow an SVM pointer, e.g. kernel enqueues and memory
1093
- copies.
1094
-
1095
- Objects of this type cannot currently be directly created or
1096
- implemented in Python. To obtain objects implementing this type,
1097
- consider its subtypes :class:`SVMAllocation` and :class:`SVM`.
1098
-
1099
-
1100
- .. property:: svm_ptr
1101
-
1102
- Gives the SVM pointer as an :class:`int`.
1103
-
1104
- .. property:: size
1105
-
1106
- An :class:`int` denoting the size in bytes, or *None*, if the size
1107
- of the SVM pointed to is not known.
1108
-
1109
- *Most* objects of this type (e.g. instances of
1110
- :class:`SVMAllocation` and :class:`SVM` know their size, so that,
1111
- for example :class:`enqueue_copy` will automatically copy an entire
1112
- :class:`SVMAllocation` when a size is not explicitly specified.
1113
-
1114
- .. automethod:: map
1115
- .. automethod:: map_ro
1116
- .. automethod:: map_rw
1117
- .. automethod:: as_buffer
1118
- .. property:: buf
1119
-
1120
- An opaque object implementing the :c:func:`Python buffer protocol
1121
- <PyObject_GetBuffer>`. It exposes the pointed-to memory as
1122
- a one-dimensional buffer of bytes, with the size matching
1123
- :attr:`size`.
1124
-
1125
- No guarantee is provided that two references to this attribute
1126
- result in the same object.
1127
- """
1128
-
1129
- def svmptr_map(self, queue: CommandQueue, *, flags: int, is_blocking: bool =
1130
- True, wait_for: Sequence[Event] | None = None,
1131
- size: Event | None = None) -> SVMMap:
1132
- """
1133
- :arg is_blocking: If *False*, subsequent code must wait on
1134
- :attr:`SVMMap.event` in the returned object before accessing the
1135
- mapped memory.
1136
- :arg flags: a combination of :class:`pyopencl.map_flags`.
1137
- :arg size: The size of the map in bytes. If not provided, defaults to
1138
- :attr:`size`.
1139
-
1140
- |std-enqueue-blurb|
1141
- """
1142
- return SVMMap(self,
1143
- np.asarray(self.buf),
1144
- queue,
1145
- _cl._enqueue_svm_map(queue, is_blocking, flags, self, wait_for,
1146
- size=size))
1147
-
1148
- def svmptr_map_ro(self, queue: CommandQueue, *, is_blocking: bool = True,
1149
- wait_for: Sequence[Event] | None = None,
1150
- size: int | None = None) -> SVMMap:
1151
- """Like :meth:`map`, but with *flags* set for a read-only map.
1152
- """
1153
-
1154
- return self.map(queue, flags=map_flags.READ,
1155
- is_blocking=is_blocking, wait_for=wait_for, size=size)
1156
-
1157
- def svmptr_map_rw(self, queue: CommandQueue, *, is_blocking: bool = True,
1158
- wait_for: Sequence[Event] | None = None,
1159
- size: int | None = None) -> SVMMap:
1160
- """Like :meth:`map`, but with *flags* set for a read-only map.
1161
- """
1162
-
1163
- return self.map(queue, flags=map_flags.READ | map_flags.WRITE,
1164
- is_blocking=is_blocking, wait_for=wait_for, size=size)
1165
-
1166
- def svmptr__enqueue_unmap(self, queue, wait_for=None):
1167
- return _cl._enqueue_svm_unmap(queue, self, wait_for)
1168
-
1169
- def svmptr_as_buffer(self, ctx: Context, *, flags: int | None = None,
1170
- size: int | None = None) -> Buffer:
1171
- """
1172
- :arg ctx: a :class:`Context`
1173
- :arg flags: a combination of :class:`pyopencl.map_flags`, defaults to
1174
- read-write.
1175
- :arg size: The size of the map in bytes. If not provided, defaults to
1176
- :attr:`size`.
1177
- :returns: a :class:`Buffer` corresponding to *self*.
1178
-
1179
- The memory referred to by this object must not be freed before
1180
- the returned :class:`Buffer` is released.
1181
- """
1182
-
1183
- if flags is None:
1184
- flags = mem_flags.READ_WRITE | mem_flags.USE_HOST_PTR
1185
-
1186
- if size is None:
1187
- size = self.size
1188
-
1189
- return Buffer(ctx, flags, size=size, hostbuf=self.buf)
1190
-
1191
- if get_cl_header_version() >= (2, 0):
1192
- SVMPointer.map = svmptr_map
1193
- SVMPointer.map_ro = svmptr_map_ro
1194
- SVMPointer.map_rw = svmptr_map_rw
1195
- SVMPointer._enqueue_unmap = svmptr__enqueue_unmap
1196
- SVMPointer.as_buffer = svmptr_as_buffer
1197
-
1198
- # }}}
1199
-
1200
- # {{{ SVMAllocation
1201
-
1202
- if get_cl_header_version() >= (2, 0):
1203
- SVMAllocation.__doc__ = """
1204
- Is a :class:`SVMPointer`.
1205
-
1206
- .. versionadded:: 2016.2
1207
-
1208
- .. automethod:: __init__
1209
-
1210
- :arg flags: See :class:`svm_mem_flags`.
1211
- :arg queue: If not specified, the allocation will be freed
1212
- eagerly, irrespective of whether pending/enqueued operations
1213
- are still using this memory.
1214
-
1215
- If specified, deallocation of the memory will be enqueued
1216
- with the given queue, and will only be performed
1217
- after previously-enqueue operations in the queue have
1218
- completed.
1219
-
1220
- It is an error to specify an out-of-order queue.
1221
-
1222
- .. warning::
1223
-
1224
- Not specifying a queue will typically lead to undesired
1225
- behavior, including crashes and memory corruption.
1226
- See the warning in :ref:`svm`.
1227
-
1228
- .. automethod:: enqueue_release
1229
-
1230
- Enqueue the release of this allocation into *queue*.
1231
- If *queue* is not specified, enqueue the deallocation
1232
- into the queue provided at allocation time or via
1233
- :class:`bind_to_queue`.
1234
-
1235
- .. automethod:: bind_to_queue
1236
-
1237
- Change the queue used for implicit enqueue of deallocation
1238
- to *queue*. Sufficient synchronization is ensured by
1239
- enqueuing a marker into the old queue and waiting on this
1240
- marker in the new queue.
1241
-
1242
- .. automethod:: unbind_from_queue
1243
-
1244
- Configure the allocation to no longer implicitly enqueue
1245
- memory allocation. If such a queue was previously provided,
1246
- :meth:`~CommandQueue.finish` is automatically called on it.
1247
- """
1248
-
1249
- # }}}
1250
-
1251
- # {{{ SVM
1252
-
1253
- if get_cl_header_version() >= (2, 0):
1254
- SVM.__doc__ = """Tags an object exhibiting the Python buffer interface
1255
- (such as a :class:`numpy.ndarray`) as referring to shared virtual
1256
- memory.
1257
-
1258
- Is a :class:`SVMPointer`, hence objects of this type may be passed
1259
- to kernel calls and :func:`enqueue_copy`, and all methods declared
1260
- there are also available there. Note that :meth:`map` differs
1261
- slightly from :meth:`SVMPointer.map`.
1262
-
1263
- Depending on the features of the OpenCL implementation, the following
1264
- types of objects may be passed to/wrapped in this type:
1265
-
1266
- * fine-grain shared memory as returned by (e.g.) :func:`fsvm_empty`,
1267
- if the implementation supports fine-grained shared virtual memory.
1268
- This memory may directly be passed to a kernel::
1269
-
1270
- ary = cl.fsvm_empty(ctx, 1000, np.float32)
1271
- assert isinstance(ary, np.ndarray)
1272
-
1273
- prg.twice(queue, ary.shape, None, cl.SVM(ary))
1274
- queue.finish() # synchronize
1275
- print(ary) # access from host
1276
-
1277
- Observe how mapping (as needed in coarse-grain SVM) is no longer
1278
- necessary.
1279
-
1280
- * any :class:`numpy.ndarray` (or other Python object with a buffer
1281
- interface) if the implementation supports fine-grained *system*
1282
- shared virtual memory.
1283
-
1284
- This is how plain :mod:`numpy` arrays may directly be passed to a
1285
- kernel::
1286
-
1287
- ary = np.zeros(1000, np.float32)
1288
- prg.twice(queue, ary.shape, None, cl.SVM(ary))
1289
- queue.finish() # synchronize
1290
- print(ary) # access from host
1291
-
1292
- * coarse-grain shared memory as returned by (e.g.) :func:`csvm_empty`
1293
- for any implementation of OpenCL 2.0.
1294
-
1295
- .. note::
1296
-
1297
- Applications making use of coarse-grain SVM may be better
1298
- served by opaque-style SVM. See :ref:`opaque-svm`.
1299
-
1300
- This is how coarse-grain SVM may be used from both host and device::
1301
-
1302
- svm_ary = cl.SVM(
1303
- cl.csvm_empty(ctx, 1000, np.float32, alignment=64))
1304
- assert isinstance(svm_ary.mem, np.ndarray)
1305
-
1306
- with svm_ary.map_rw(queue) as ary:
1307
- ary.fill(17) # use from host
1308
-
1309
- prg.twice(queue, svm_ary.mem.shape, None, svm_ary)
1310
-
1311
- Coarse-grain shared-memory *must* be mapped into host address space
1312
- using :meth:`~SVMPointer.map` before being accessed through the
1313
- :mod:`numpy` interface.
1314
-
1315
- .. note::
1316
-
1317
- This object merely serves as a 'tag' that changes the behavior
1318
- of functions to which it is passed. It has no special management
1319
- relationship to the memory it tags. For example, it is permissible
1320
- to grab a :class:`numpy.ndarray` out of :attr:`SVM.mem` of one
1321
- :class:`SVM` instance and use the array to construct another.
1322
- Neither of the tags need to be kept alive.
1323
-
1324
- .. versionadded:: 2016.2
1325
-
1326
- .. attribute:: mem
1327
-
1328
- The wrapped object.
1329
-
1330
- .. automethod:: __init__
1331
- .. automethod:: map
1332
- .. automethod:: map_ro
1333
- .. automethod:: map_rw
1334
- """
1335
-
1336
- # }}}
1337
-
1338
- def svm_map(self, queue, flags, is_blocking=True, wait_for=None):
1339
- """
1340
- :arg is_blocking: If *False*, subsequent code must wait on
1341
- :attr:`SVMMap.event` in the returned object before accessing the
1342
- mapped memory.
1343
- :arg flags: a combination of :class:`pyopencl.map_flags`.
1344
- :returns: an :class:`SVMMap` instance
1345
-
1346
- This differs from the inherited :class:`SVMPointer.map` in that no size
1347
- can be specified, and that :attr:`mem` is the exact array produced
1348
- when the :class:`SVMMap` is used as a context manager.
1349
-
1350
- |std-enqueue-blurb|
1351
- """
1352
- return SVMMap(
1353
- self,
1354
- self.mem,
1355
- queue,
1356
- _cl._enqueue_svm_map(queue, is_blocking, flags, self, wait_for))
1357
-
1358
- def svm_map_ro(self, queue, is_blocking=True, wait_for=None):
1359
- """Like :meth:`map`, but with *flags* set for a read-only map."""
1360
-
1361
- return self.map(queue, map_flags.READ,
1362
- is_blocking=is_blocking, wait_for=wait_for)
1363
-
1364
- def svm_map_rw(self, queue, is_blocking=True, wait_for=None):
1365
- """Like :meth:`map`, but with *flags* set for a read-only map."""
1366
-
1367
- return self.map(queue, map_flags.READ | map_flags.WRITE,
1368
- is_blocking=is_blocking, wait_for=wait_for)
1369
-
1370
- def svm__enqueue_unmap(self, queue, wait_for=None):
1371
- return _cl._enqueue_svm_unmap(queue, self, wait_for)
1372
-
1373
- if get_cl_header_version() >= (2, 0):
1374
- SVM.map = svm_map
1375
- SVM.map_ro = svm_map_ro
1376
- SVM.map_rw = svm_map_rw
1377
- SVM._enqueue_unmap = svm__enqueue_unmap
1378
-
1379
- # }}}
1380
-
1381
- # ORDER DEPENDENCY: Some of the above may override get_info, the effect needs
1382
- # to be visible through the attributes. So get_info attr creation needs to happen
1383
- # after the overriding is complete.
1384
- cls_to_info_cls = {
1385
- _cl.Platform: (_cl.Platform.get_info, _cl.platform_info, []),
1386
- _cl.Device: (_cl.Device.get_info, _cl.device_info,
1387
- ["PLATFORM", "MAX_WORK_GROUP_SIZE", "MAX_COMPUTE_UNITS"]),
1388
- _cl.Context: (_cl.Context.get_info, _cl.context_info, []),
1389
- _cl.CommandQueue: (_cl.CommandQueue.get_info, _cl.command_queue_info,
1390
- ["CONTEXT", "DEVICE"]),
1391
- _cl.Event: (_cl.Event.get_info, _cl.event_info, []),
1392
- _cl.MemoryObjectHolder:
1393
- (MemoryObjectHolder.get_info, _cl.mem_info, []),
1394
- Image: (_cl.Image.get_image_info, _cl.image_info, []),
1395
- Pipe: (_cl.Pipe.get_pipe_info, _cl.pipe_info, []),
1396
- Program: (Program.get_info, _cl.program_info, []),
1397
- Kernel: (Kernel.get_info, _cl.kernel_info, []),
1398
- _cl.Sampler: (Sampler.get_info, _cl.sampler_info, []),
1399
- }
1400
-
1401
- def to_string(cls, value, default_format=None):
1402
- if cls._is_bitfield:
1403
- names = []
1404
- for name in dir(cls):
1405
- attr = getattr(cls, name)
1406
- if not isinstance(attr, int):
1407
- continue
1408
- if attr == value or attr & value:
1409
- names.append(name)
1410
- if names:
1411
- return " | ".join(names)
1412
- else:
1413
- for name in dir(cls):
1414
- if (not name.startswith("_")
1415
- and getattr(cls, name) == value):
1416
- return name
1417
-
1418
- if default_format is None:
1419
- raise ValueError("a name for value %d was not found in %s"
1420
- % (value, cls.__name__))
1421
- else:
1422
- return default_format % value
1423
-
1424
- for cls in CONSTANT_CLASSES:
1425
- cls._is_bitfield = cls in BITFIELD_CONSTANT_CLASSES
1426
- cls.to_string = classmethod(to_string)
1427
-
1428
- # {{{ get_info attributes -------------------------------------------------
1429
-
1430
- def make_getinfo(info_method, info_name, info_attr):
1431
- def result(self):
1432
- return info_method(self, info_attr)
1433
-
1434
- return property(result)
1435
-
1436
- def make_cacheable_getinfo(info_method, info_name, cache_attr, info_attr):
1437
- def result(self):
1438
- try:
1439
- return getattr(self, cache_attr)
1440
- except AttributeError:
1441
- pass
1442
-
1443
- result = info_method(self, info_attr)
1444
- setattr(self, cache_attr, result)
1445
- return result
1446
-
1447
- return property(result)
1448
-
1449
- for cls, (info_method, info_class, cacheable_attrs) \
1450
- in cls_to_info_cls.items():
1451
- for info_name, _info_value in info_class.__dict__.items():
1452
- if info_name == "to_string" or info_name.startswith("_"):
1453
- continue
1454
-
1455
- info_lower = info_name.lower()
1456
- info_constant = getattr(info_class, info_name)
1457
- if info_name in cacheable_attrs:
1458
- cache_attr = intern("_info_cache_"+info_lower)
1459
- setattr(cls, info_lower, make_cacheable_getinfo(
1460
- info_method, info_lower, cache_attr, info_constant))
1461
- else:
1462
- setattr(cls, info_lower, make_getinfo(
1463
- info_method, info_name, info_constant))
1464
-
1465
- # }}}
1466
-
1467
- if _cl.have_gl():
1468
- def gl_object_get_gl_object(self):
1469
- return self.get_gl_object_info()[1]
1470
-
1471
- GLBuffer.gl_object = property(gl_object_get_gl_object)
1472
- GLTexture.gl_object = property(gl_object_get_gl_object)
1473
-
1474
-
1475
- _add_functionality()
1476
-
1477
- # }}}
1478
-
1479
-
1480
694
  # {{{ _OverriddenArrayInterfaceSVMAllocation
1481
695
 
1482
696
  if get_cl_header_version() >= (2, 0):
@@ -1597,7 +811,21 @@ def choose_devices(interactive: bool | None = None,
1597
811
 
1598
812
  # {{{ pick a platform
1599
813
 
1600
- platforms = get_platforms()
814
+ try:
815
+ platforms = get_platforms()
816
+ except LogicError as e:
817
+ if "PLATFORM_NOT_FOUND_KHR" in str(e):
818
+ # With the cl_khr_icd extension, clGetPlatformIDs fails if no platform
819
+ # is available:
820
+ # https://registry.khronos.org/OpenCL/sdk/3.0/docs/man/html/clGetPlatformIDs.html
821
+ raise RuntimeError("no CL platforms available to ICD loader. "
822
+ "Install a CL driver "
823
+ "('ICD', such as pocl, rocm, Intel CL) to fix this. "
824
+ "See pyopencl docs for help: "
825
+ "https://documen.tician.de/pyopencl/"
826
+ "misc.html#installation") from e
827
+ else:
828
+ raise
1601
829
 
1602
830
  if not platforms:
1603
831
  raise Error("no platforms found")
@@ -1708,7 +936,8 @@ _csc = create_some_context
1708
936
 
1709
937
  # {{{ SVMMap
1710
938
 
1711
- class SVMMap:
939
+ @dataclass
940
+ class SVMMap(Generic[SVMInnerT]):
1712
941
  """
1713
942
  Returned by :func:`SVMPointer.map` and :func:`SVM.map`.
1714
943
  This class may also be used as a context manager in a ``with`` statement.
@@ -1725,11 +954,10 @@ class SVMMap:
1725
954
  .. automethod:: release
1726
955
 
1727
956
  """
1728
- def __init__(self, svm, array, queue, event):
1729
- self.svm = svm
1730
- self.array = array
1731
- self.queue = queue
1732
- self.event = event
957
+ svm: SVM[SVMInnerT] | None
958
+ array: SVMInnerT
959
+ queue: CommandQueue
960
+ event: Event
1733
961
 
1734
962
  def __del__(self):
1735
963
  if self.svm is not None:
@@ -1741,7 +969,10 @@ class SVMMap:
1741
969
  def __exit__(self, exc_type, exc_val, exc_tb):
1742
970
  self.release()
1743
971
 
1744
- def release(self, queue=None, wait_for=None):
972
+ def release(self,
973
+ queue: CommandQueue | None = None,
974
+ wait_for: WaitList = None
975
+ ) -> Event:
1745
976
  """
1746
977
  :arg queue: a :class:`pyopencl.CommandQueue`. Defaults to the one
1747
978
  with which the map was created, if not specified.
@@ -1750,7 +981,8 @@ class SVMMap:
1750
981
  |std-enqueue-blurb|
1751
982
  """
1752
983
 
1753
- evt = self.svm._enqueue_unmap(self.queue)
984
+ assert self.svm is not None
985
+ evt = self.svm._enqueue_unmap(queue or self.queue, wait_for)
1754
986
  self.svm = None
1755
987
 
1756
988
  return evt
@@ -1765,7 +997,164 @@ if get_cl_header_version() >= (1, 2):
1765
997
  _IMAGE_MEM_OBJ_TYPES.append(mem_object_type.IMAGE2D_ARRAY)
1766
998
 
1767
999
 
1768
- def enqueue_copy(queue, dest, src, **kwargs):
1000
+ @overload
1001
+ def enqueue_copy(
1002
+ queue: CommandQueue,
1003
+ dest: Buffer,
1004
+ src: HasBufferInterface,
1005
+ *,
1006
+ dst_offset: int = 0,
1007
+ is_blocking: bool = True,
1008
+ wait_for: WaitList = None
1009
+ ) -> Event: ...
1010
+
1011
+ @overload
1012
+ def enqueue_copy(
1013
+ queue: CommandQueue,
1014
+ dest: HasBufferInterface,
1015
+ src: Buffer,
1016
+ *,
1017
+ src_offset: int = 0,
1018
+ is_blocking: bool = True,
1019
+ wait_for: WaitList = None
1020
+ ) -> Event: ...
1021
+
1022
+ @overload
1023
+ def enqueue_copy(
1024
+ queue: CommandQueue,
1025
+ dest: Buffer,
1026
+ src: Buffer,
1027
+ *,
1028
+ src_offset: int = 0,
1029
+ dst_offset: int = 0,
1030
+ byte_count: int | None = None,
1031
+ wait_for: WaitList = None
1032
+ ) -> Event: ...
1033
+
1034
+ @overload
1035
+ def enqueue_copy(
1036
+ queue: CommandQueue,
1037
+ dest: Buffer,
1038
+ src: HasBufferInterface,
1039
+ *,
1040
+ origin: tuple[int, ...],
1041
+ host_origin: tuple[int, ...],
1042
+ region: tuple[int, ...],
1043
+ buffer_pitches: tuple[int, ...] | None = None,
1044
+ host_pitches: tuple[int, ...] | None = None,
1045
+ is_blocking: bool = True,
1046
+ wait_for: WaitList = None
1047
+ ) -> Event: ...
1048
+
1049
+ @overload
1050
+ def enqueue_copy(
1051
+ queue: CommandQueue,
1052
+ dest: HasBufferInterface,
1053
+ src: Buffer,
1054
+ *,
1055
+ origin: tuple[int, ...],
1056
+ host_origin: tuple[int, ...],
1057
+ region: tuple[int, ...],
1058
+ buffer_pitches: tuple[int, ...] | None = None,
1059
+ host_pitches: tuple[int, ...] | None = None,
1060
+ is_blocking: bool = True,
1061
+ wait_for: WaitList = None
1062
+ ) -> Event: ...
1063
+
1064
+ @overload
1065
+ def enqueue_copy(
1066
+ queue: CommandQueue,
1067
+ dest: Buffer,
1068
+ src: Buffer,
1069
+ *,
1070
+ src_origin: tuple[int, ...],
1071
+ dst_origin: tuple[int, ...],
1072
+ region: tuple[int, ...],
1073
+ src_pitches: tuple[int, ...] | None = None,
1074
+ dst_pitches: tuple[int, ...] | None = None,
1075
+ wait_for: WaitList = None
1076
+ ) -> Event: ...
1077
+
1078
+ @overload
1079
+ def enqueue_copy(
1080
+ queue: CommandQueue,
1081
+ dest: HasBufferInterface,
1082
+ src: Image,
1083
+ *,
1084
+ origin: tuple[int, ...],
1085
+ region: tuple[int, ...],
1086
+ pitches: tuple[int, ...] | None = None,
1087
+ is_blocking: bool = True,
1088
+ wait_for: WaitList = None
1089
+ ) -> Event: ...
1090
+
1091
+ @overload
1092
+ def enqueue_copy(
1093
+ queue: CommandQueue,
1094
+ dest: Image,
1095
+ src: HasBufferInterface,
1096
+ *,
1097
+ origin: tuple[int, ...],
1098
+ region: tuple[int, ...],
1099
+ pitches: tuple[int, ...] | None = None,
1100
+ is_blocking: bool = True,
1101
+ wait_for: WaitList = None
1102
+ ) -> Event: ...
1103
+
1104
+ @overload
1105
+ def enqueue_copy(
1106
+ queue: CommandQueue,
1107
+ dest: Image,
1108
+ src: Buffer,
1109
+ *,
1110
+ origin: tuple[int, ...],
1111
+ region: tuple[int, ...],
1112
+ pitches: tuple[int, ...] | None = None,
1113
+ wait_for: WaitList = None
1114
+ ) -> Event: ...
1115
+
1116
+ @overload
1117
+ def enqueue_copy(
1118
+ queue: CommandQueue,
1119
+ dest: Buffer,
1120
+ src: Image,
1121
+ *,
1122
+ origin: tuple[int, ...],
1123
+ region: tuple[int, ...],
1124
+ pitches: tuple[int, ...] | None = None,
1125
+ wait_for: WaitList = None
1126
+ ) -> Event: ...
1127
+
1128
+ @overload
1129
+ def enqueue_copy(
1130
+ queue: CommandQueue,
1131
+ dest: Image,
1132
+ src: Image,
1133
+ *,
1134
+ src_origin: tuple[int, ...],
1135
+ dest_origin: tuple[int, ...],
1136
+ region: tuple[int, ...],
1137
+ wait_for: WaitList = None
1138
+ ) -> Event: ...
1139
+
1140
+ @overload
1141
+ def enqueue_copy(
1142
+ queue: CommandQueue,
1143
+ dest: SVMPointer | HasBufferInterface,
1144
+ src: SVMPointer | HasBufferInterface,
1145
+ *,
1146
+ byte_count: int | None = None,
1147
+
1148
+ # do not use, must be zero
1149
+ src_offset: int = 0,
1150
+ dst_offset: int = 0,
1151
+
1152
+ is_blocking: bool = True,
1153
+ wait_for: WaitList = None
1154
+ ) -> Event: ...
1155
+
1156
+
1157
+ def enqueue_copy(queue: CommandQueue, dest: Any, src: Any, **kwargs: Any) -> Event:
1769
1158
  """Copy from :class:`Image`, :class:`Buffer` or the host to
1770
1159
  :class:`Image`, :class:`Buffer` or the host. (Note: host-to-host
1771
1160
  copies are unsupported.)
@@ -2071,9 +1460,11 @@ def enqueue_copy(queue, dest, src, **kwargs):
2071
1460
  # {{{ enqueue_fill
2072
1461
 
2073
1462
  def enqueue_fill(queue: CommandQueue,
2074
- dest: MemoryObject | SVMPointer,
2075
- pattern: Any, size: int, *, offset: int = 0,
2076
- wait_for: Sequence[Event] | None = None) -> Event:
1463
+ dest: MemoryObjectHolder | SVMPointer,
1464
+ pattern: HasBufferInterface,
1465
+ size: int,
1466
+ *, offset: int = 0,
1467
+ wait_for: WaitList = None) -> Event:
2077
1468
  """
2078
1469
  .. versionadded:: 2022.2
2079
1470
  """
@@ -2116,7 +1507,13 @@ DTYPE_TO_CHANNEL_TYPE_NORM = {
2116
1507
  }
2117
1508
 
2118
1509
 
2119
- def image_from_array(ctx, ary, num_channels=None, mode="r", norm_int=False):
1510
+ def image_from_array(
1511
+ ctx: Context,
1512
+ ary: NDArray[Any],
1513
+ num_channels: int | None = None,
1514
+ mode: Literal["r"] | Literal["w"] = "r",
1515
+ norm_int: bool = False
1516
+ ) -> Image:
2120
1517
  if not ary.flags.c_contiguous:
2121
1518
  raise ValueError("array must be C-contiguous")
2122
1519
 
@@ -2174,7 +1571,7 @@ def image_from_array(ctx, ary, num_channels=None, mode="r", norm_int=False):
2174
1571
 
2175
1572
  # {{{ enqueue_* compatibility shims
2176
1573
 
2177
- def enqueue_marker(queue, wait_for=None):
1574
+ def enqueue_marker(queue: CommandQueue, wait_for: WaitList = None) -> Event:
2178
1575
  if queue._get_cl_version() >= (1, 2) and get_cl_header_version() >= (1, 2):
2179
1576
  return _cl._enqueue_marker_with_wait_list(queue, wait_for)
2180
1577
  else:
@@ -2183,7 +1580,7 @@ def enqueue_marker(queue, wait_for=None):
2183
1580
  return _cl._enqueue_marker(queue)
2184
1581
 
2185
1582
 
2186
- def enqueue_barrier(queue, wait_for=None):
1583
+ def enqueue_barrier(queue: CommandQueue, wait_for: WaitList = None) -> Event:
2187
1584
  if queue._get_cl_version() >= (1, 2) and get_cl_header_version() >= (1, 2):
2188
1585
  return _cl._enqueue_barrier_with_wait_list(queue, wait_for)
2189
1586
  else:
@@ -2193,7 +1590,14 @@ def enqueue_barrier(queue, wait_for=None):
2193
1590
  return _cl._enqueue_marker(queue)
2194
1591
 
2195
1592
 
2196
- def enqueue_fill_buffer(queue, mem, pattern, offset, size, wait_for=None):
1593
+ def enqueue_fill_buffer(
1594
+ queue: CommandQueue,
1595
+ mem: MemoryObjectHolder,
1596
+ pattern: HasBufferInterface,
1597
+ offset: int,
1598
+ size: int,
1599
+ wait_for: WaitList = None
1600
+ ) -> Event:
2197
1601
  if not (queue._get_cl_version() >= (1, 2) and get_cl_header_version() >= (1, 2)):
2198
1602
  warn(
2199
1603
  "The context for this queue does not declare OpenCL 1.2 support, so "
@@ -2203,14 +1607,21 @@ def enqueue_fill_buffer(queue, mem, pattern, offset, size, wait_for=None):
2203
1607
  if _PYPY and isinstance(pattern, np.generic):
2204
1608
  pattern = np.asarray(pattern)
2205
1609
 
2206
- return _cl._enqueue_fill_buffer(queue, mem, pattern, offset, size, wait_for)
1610
+ return _cl._enqueue_fill_buffer(queue, mem, pattern, offset, size,
1611
+ wait_for)
2207
1612
 
2208
1613
  # }}}
2209
1614
 
2210
1615
 
2211
1616
  # {{{ numpy-like svm allocation
2212
1617
 
2213
- def enqueue_svm_memfill(queue, dest, pattern, byte_count=None, wait_for=None):
1618
+ def enqueue_svm_memfill(
1619
+ queue: CommandQueue,
1620
+ dest: SVMPointer,
1621
+ pattern: HasBufferInterface,
1622
+ byte_count: int | None = None,
1623
+ wait_for: WaitList = None
1624
+ ) -> Event:
2214
1625
  """Fill shared virtual memory with a pattern.
2215
1626
 
2216
1627
  :arg dest: a Python buffer object, or any implementation of :class:`SVMPointer`.
@@ -2231,7 +1642,12 @@ def enqueue_svm_memfill(queue, dest, pattern, byte_count=None, wait_for=None):
2231
1642
  queue, dest, pattern, byte_count=byte_count, wait_for=wait_for)
2232
1643
 
2233
1644
 
2234
- def enqueue_svm_migratemem(queue, svms, flags, wait_for=None):
1645
+ def enqueue_svm_migrate_mem(
1646
+ queue: CommandQueue,
1647
+ svms: Sequence[SVMPointer],
1648
+ flags: svm_mem_flags,
1649
+ wait_for: WaitList = None,
1650
+ ):
2235
1651
  """
2236
1652
  :arg svms: a collection of Python buffer objects (e.g. :mod:`numpy`
2237
1653
  arrays), or any implementation of :class:`SVMPointer`.
@@ -2244,10 +1660,18 @@ def enqueue_svm_migratemem(queue, svms, flags, wait_for=None):
2244
1660
  This function requires OpenCL 2.1.
2245
1661
  """
2246
1662
 
2247
- return _cl._enqueue_svm_migratemem(queue, svms, flags, wait_for)
1663
+ return _cl._enqueue_svm_migrate_mem(queue, svms, flags, wait_for)
2248
1664
 
2249
1665
 
2250
- def svm_empty(ctx, flags, shape, dtype, order="C", alignment=None, queue=None):
1666
+ def svm_empty(
1667
+ ctx: Context,
1668
+ flags: svm_mem_flags,
1669
+ shape: int | tuple[int, ...],
1670
+ dtype: DTypeT,
1671
+ order: Literal["F"] | Literal["C"] = "C",
1672
+ alignment: int | None = None,
1673
+ queue: CommandQueue | None = None,
1674
+ ) -> np.ndarray[tuple[int, ...], DTypeT]:
2251
1675
  """Allocate an empty :class:`numpy.ndarray` of the given *shape*, *dtype*
2252
1676
  and *order*. (See :func:`numpy.empty` for the meaning of these arguments.)
2253
1677
  The array will be allocated in shared virtual memory belonging
@@ -2274,6 +1698,7 @@ def svm_empty(ctx, flags, shape, dtype, order="C", alignment=None, queue=None):
2274
1698
  dtype = np.dtype(dtype)
2275
1699
 
2276
1700
  try:
1701
+ shape = cast("tuple[int, ...]", shape)
2277
1702
  s = 1
2278
1703
  for dim in shape:
2279
1704
  s *= dim
@@ -2321,13 +1746,16 @@ def svm_empty(ctx, flags, shape, dtype, order="C", alignment=None, queue=None):
2321
1746
  return np.asarray(svm_alloc)
2322
1747
 
2323
1748
 
2324
- def svm_empty_like(ctx, flags, ary, alignment=None):
1749
+ def svm_empty_like(
1750
+ ctx: Context,
1751
+ flags: svm_mem_flags,
1752
+ ary: np.ndarray[tuple[int, ...], DTypeT],
1753
+ alignment: int | None = None,
1754
+ ) -> np.ndarray[tuple[int, ...], DTypeT]:
2325
1755
  """Allocate an empty :class:`numpy.ndarray` like the existing
2326
1756
  :class:`numpy.ndarray` *ary*. The array will be allocated in shared
2327
1757
  virtual memory belonging to *ctx*.
2328
1758
 
2329
- :arg ctx: a :class:`Context`
2330
- :arg flags: a combination of flags from :class:`svm_mem_flags`.
2331
1759
  :arg alignment: the number of bytes to which the beginning of the memory
2332
1760
  is aligned. Defaults to the :attr:`numpy.dtype.itemsize` of *dtype*.
2333
1761
 
@@ -2350,27 +1778,46 @@ def svm_empty_like(ctx, flags, ary, alignment=None):
2350
1778
  alignment=alignment)
2351
1779
 
2352
1780
 
2353
- def csvm_empty(ctx, shape, dtype, order="C", alignment=None):
1781
+ def csvm_empty(
1782
+ ctx: Context,
1783
+ shape: int | tuple[int, ...],
1784
+ dtype: DTypeT,
1785
+ order: Literal["F"] | Literal["C"] = "C",
1786
+ alignment: int | None = None,
1787
+ queue: CommandQueue | None = None,
1788
+ ) -> np.ndarray[tuple[int, ...], DTypeT]:
2354
1789
  """
2355
1790
  Like :func:`svm_empty`, but with *flags* set for a coarse-grain read-write
2356
1791
  buffer.
2357
1792
 
2358
1793
  .. versionadded:: 2016.2
2359
1794
  """
2360
- return svm_empty(ctx, svm_mem_flags.READ_WRITE, shape, dtype, order, alignment)
1795
+ return svm_empty(ctx, svm_mem_flags.READ_WRITE, shape, dtype, order,
1796
+ alignment, queue=queue)
2361
1797
 
2362
1798
 
2363
- def csvm_empty_like(ctx, ary, alignment=None):
1799
+ def csvm_empty_like(
1800
+ ctx: Context,
1801
+ ary: np.ndarray[tuple[int, ...], DTypeT],
1802
+ alignment: int | None = None,
1803
+ ) -> np.ndarray[tuple[int, ...], DTypeT]:
2364
1804
  """
2365
1805
  Like :func:`svm_empty_like`, but with *flags* set for a coarse-grain
2366
1806
  read-write buffer.
2367
1807
 
2368
1808
  .. versionadded:: 2016.2
2369
1809
  """
2370
- return svm_empty_like(ctx, svm_mem_flags.READ_WRITE, ary)
1810
+ return svm_empty_like(ctx, svm_mem_flags.READ_WRITE, ary, alignment)
2371
1811
 
2372
1812
 
2373
- def fsvm_empty(ctx, shape, dtype, order="C", alignment=None):
1813
+ def fsvm_empty(
1814
+ ctx: Context,
1815
+ shape: int | tuple[int, ...],
1816
+ dtype: DTypeT,
1817
+ order: Literal["F"] | Literal["C"] = "C",
1818
+ alignment: int | None = None,
1819
+ queue: CommandQueue | None = None,
1820
+ ) -> np.ndarray[tuple[int, ...], DTypeT]:
2374
1821
  """
2375
1822
  Like :func:`svm_empty`, but with *flags* set for a fine-grain read-write
2376
1823
  buffer.
@@ -2379,10 +1826,14 @@ def fsvm_empty(ctx, shape, dtype, order="C", alignment=None):
2379
1826
  """
2380
1827
  return svm_empty(ctx,
2381
1828
  svm_mem_flags.READ_WRITE | svm_mem_flags.SVM_FINE_GRAIN_BUFFER,
2382
- shape, dtype, order, alignment)
1829
+ shape, dtype, order, alignment, queue)
2383
1830
 
2384
1831
 
2385
- def fsvm_empty_like(ctx, ary, alignment=None):
1832
+ def fsvm_empty_like(
1833
+ ctx: Context,
1834
+ ary: np.ndarray[tuple[int, ...], DTypeT],
1835
+ alignment: int | None = None,
1836
+ ) -> np.ndarray[tuple[int, ...], DTypeT]:
2386
1837
  """
2387
1838
  Like :func:`svm_empty_like`, but with *flags* set for a fine-grain
2388
1839
  read-write buffer.
@@ -2392,7 +1843,8 @@ def fsvm_empty_like(ctx, ary, alignment=None):
2392
1843
  return svm_empty_like(
2393
1844
  ctx,
2394
1845
  svm_mem_flags.READ_WRITE | svm_mem_flags.SVM_FINE_GRAIN_BUFFER,
2395
- ary)
1846
+ ary,
1847
+ alignment)
2396
1848
 
2397
1849
  # }}}
2398
1850
 
@@ -2402,9 +1854,142 @@ _KERNEL_ARG_CLASSES: tuple[type, ...] = (
2402
1854
  Sampler,
2403
1855
  CommandQueue,
2404
1856
  LocalMemory,
1857
+ *([SVM] if get_cl_header_version() >= (2, 0) else [])
2405
1858
  )
2406
- if get_cl_header_version() >= (2, 0):
2407
- _KERNEL_ARG_CLASSES = (*_KERNEL_ARG_CLASSES, SVM)
1859
+
1860
+
1861
+ CtxFactory: TypeAlias = Callable[[], Context]
1862
+
1863
+
1864
+ __all__ = [
1865
+ "SVM",
1866
+ "VERSION",
1867
+ "VERSION_STATUS",
1868
+ "VERSION_TEXT",
1869
+ "Buffer",
1870
+ "CommandQueue",
1871
+ "Context",
1872
+ "CtxFactory",
1873
+ "Device",
1874
+ "DeviceTopologyAmd",
1875
+ "Error",
1876
+ "Event",
1877
+ "GLBuffer",
1878
+ "GLRenderBuffer",
1879
+ "GLTexture",
1880
+ "Image",
1881
+ "ImageDescriptor",
1882
+ "ImageFormat",
1883
+ "Kernel",
1884
+ "LocalMemory",
1885
+ "LogicError",
1886
+ "MemoryError",
1887
+ "MemoryMap",
1888
+ "MemoryObject",
1889
+ "MemoryObjectHolder",
1890
+ "NannyEvent",
1891
+ "Pipe",
1892
+ "Platform",
1893
+ "Program",
1894
+ "RuntimeError",
1895
+ "SVMAllocation",
1896
+ "SVMAllocation",
1897
+ "SVMMap",
1898
+ "SVMPointer",
1899
+ "Sampler",
1900
+ "UserEvent",
1901
+ "WaitList",
1902
+ "_csc",
1903
+ "addressing_mode",
1904
+ "channel_order",
1905
+ "channel_type",
1906
+ "choose_devices",
1907
+ "command_execution_status",
1908
+ "command_queue_info",
1909
+ "command_queue_properties",
1910
+ "command_type",
1911
+ "context_info",
1912
+ "context_properties",
1913
+ "create_image",
1914
+ "create_program_with_built_in_kernels",
1915
+ "create_some_context",
1916
+ "csvm_empty",
1917
+ "csvm_empty_like",
1918
+ "device_affinity_domain",
1919
+ "device_atomic_capabilities",
1920
+ "device_device_enqueue_capabilities",
1921
+ "device_exec_capabilities",
1922
+ "device_fp_config",
1923
+ "device_info",
1924
+ "device_local_mem_type",
1925
+ "device_mem_cache_type",
1926
+ "device_partition_property",
1927
+ "device_svm_capabilities",
1928
+ "device_topology_type_amd",
1929
+ "device_type",
1930
+ "enable_debugging",
1931
+ "enqueue_acquire_gl_objects",
1932
+ "enqueue_barrier",
1933
+ "enqueue_copy",
1934
+ "enqueue_copy_buffer_p2p_amd",
1935
+ "enqueue_fill",
1936
+ "enqueue_fill_buffer",
1937
+ "enqueue_fill_image",
1938
+ "enqueue_map_buffer",
1939
+ "enqueue_map_image",
1940
+ "enqueue_marker",
1941
+ "enqueue_migrate_mem_objects",
1942
+ "enqueue_nd_range_kernel",
1943
+ "enqueue_release_gl_objects",
1944
+ "enqueue_svm_memfill",
1945
+ "enqueue_svm_migrate_mem",
1946
+ "event_info",
1947
+ "filter_mode",
1948
+ "fsvm_empty",
1949
+ "fsvm_empty_like",
1950
+ "get_apple_cgl_share_group",
1951
+ "get_cl_header_version",
1952
+ "get_platforms",
1953
+ "get_supported_image_formats",
1954
+ "gl_context_info",
1955
+ "gl_object_type",
1956
+ "gl_texture_info",
1957
+ "have_gl",
1958
+ "image_from_array",
1959
+ "image_info",
1960
+ "kernel_arg_access_qualifier",
1961
+ "kernel_arg_address_qualifier",
1962
+ "kernel_arg_info",
1963
+ "kernel_arg_type_qualifier",
1964
+ "kernel_info",
1965
+ "kernel_sub_group_info",
1966
+ "kernel_work_group_info",
1967
+ "khronos_vendor_id",
1968
+ "link_program",
1969
+ "map_flags",
1970
+ "mem_flags",
1971
+ "mem_info",
1972
+ "mem_migration_flags",
1973
+ "mem_object_type",
1974
+ "pipe_info",
1975
+ "pipe_properties",
1976
+ "platform_info",
1977
+ "profiling_info",
1978
+ "program_binary_type",
1979
+ "program_build_info",
1980
+ "program_info",
1981
+ "program_kind",
1982
+ "queue_properties",
1983
+ "sampler_info",
1984
+ "sampler_properties",
1985
+ "status_code",
1986
+ "svm_empty",
1987
+ "svm_empty_like",
1988
+ "svm_mem_flags",
1989
+ "unload_platform_compiler",
1990
+ "version_bits",
1991
+ "wait_for_events",
1992
+ ]
2408
1993
 
2409
1994
 
2410
1995
  # vim: foldmethod=marker