pyopencl 2025.1__cp311-cp311-macosx_10_14_x86_64.whl → 2025.2.2__cp311-cp311-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 +582 -997
- pyopencl/_cl.cpython-311-darwin.so +0 -0
- pyopencl/_cl.pyi +2006 -0
- pyopencl/_cluda.py +3 -0
- pyopencl/_monkeypatch.py +1063 -0
- pyopencl/_mymako.py +3 -0
- pyopencl/algorithm.py +29 -24
- pyopencl/array.py +300 -255
- pyopencl/bitonic_sort.py +5 -2
- pyopencl/bitonic_sort_templates.py +3 -0
- pyopencl/cache.py +5 -5
- pyopencl/capture_call.py +31 -8
- pyopencl/characterize/__init__.py +26 -19
- pyopencl/characterize/performance.py +3 -0
- pyopencl/clmath.py +2 -0
- pyopencl/clrandom.py +3 -0
- pyopencl/cltypes.py +67 -2
- pyopencl/compyte/.basedpyright/baseline.json +1272 -0
- pyopencl/compyte/array.py +36 -9
- pyopencl/compyte/dtypes.py +61 -29
- pyopencl/compyte/pyproject.toml +17 -22
- pyopencl/elementwise.py +13 -10
- pyopencl/invoker.py +13 -17
- pyopencl/ipython_ext.py +2 -0
- pyopencl/py.typed +0 -0
- pyopencl/reduction.py +72 -43
- pyopencl/scan.py +31 -30
- pyopencl/tools.py +128 -90
- pyopencl/typing.py +57 -0
- pyopencl/version.py +2 -0
- {pyopencl-2025.1.dist-info → pyopencl-2025.2.2.dist-info}/METADATA +11 -10
- pyopencl-2025.2.2.dist-info/RECORD +47 -0
- {pyopencl-2025.1.dist-info → pyopencl-2025.2.2.dist-info}/WHEEL +2 -1
- pyopencl-2025.1.dist-info/RECORD +0 -42
- {pyopencl-2025.1.dist-info → pyopencl-2025.2.2.dist-info}/licenses/LICENSE +0 -0
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
|
|
28
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
180
|
-
from
|
|
181
|
-
from pyopencl._cl import
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
192
|
-
if get_cl_header_version() >= (1, 2):
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
227
|
+
if get_cl_header_version() >= (2, 0):
|
|
228
|
+
from pyopencl._cl import SVM, SVMAllocation, SVMPointer
|
|
201
229
|
|
|
202
|
-
if _cl.have_gl():
|
|
203
|
-
|
|
204
|
-
|
|
230
|
+
if _cl.have_gl():
|
|
231
|
+
from pyopencl._cl import (
|
|
232
|
+
GLBuffer, GLRenderBuffer, GLTexture, gl_object_type, gl_texture_info)
|
|
205
233
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
234
|
+
try:
|
|
235
|
+
from pyopencl._cl import get_apple_cgl_share_group
|
|
236
|
+
except ImportError:
|
|
237
|
+
pass
|
|
210
238
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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,
|
|
435
|
+
context, devices, binaries = arg1, arg2, arg3
|
|
406
436
|
self._context = context
|
|
407
|
-
self._prg = _cl._Program(context,
|
|
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,
|
|
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 = (
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
2075
|
-
pattern:
|
|
2076
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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
|
|
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.
|
|
1663
|
+
return _cl._enqueue_svm_migrate_mem(queue, svms, flags, wait_for)
|
|
2248
1664
|
|
|
2249
1665
|
|
|
2250
|
-
def svm_empty(
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
2407
|
-
|
|
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
|