Coverage for cuda/core/texture/_surface.pyx: 76.32%
38 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-19 01:12 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-19 01:12 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from __future__ import annotations
7from libc.string cimport memset
9from cuda.bindings cimport cydriver
10from cuda.core.texture._array cimport OpaqueArray
11from cuda.core._resource_handles cimport (
12 SurfObjectHandle,
13 as_cu,
14 as_intptr,
15 create_surf_object_handle,
16 get_last_error,
17)
18from cuda.core.texture._texture import ResourceDescriptor
19from cuda.core._utils.cuda_utils cimport (
20 HANDLE_RETURN,
21 _get_current_device_id,
22)
25cdef class SurfaceObject:
26 """A bindless surface handle for kernel-side typed load/store.
28 Wraps ``cuSurfObjectCreate``. Unlike a :class:`TextureObject`, a surface
29 has no sampling state (no filtering, no addressing modes, no normalization);
30 kernels read and write through it using integer pixel coordinates.
32 The backing :class:`OpaqueArray` must have been created with
33 ``is_surface_load_store=True`` and is kept alive for the lifetime of this
34 object to prevent dangling handles.
36 Construct via :meth:`cuda.core.Device.create_surface_object`. Passes to
37 kernels as a 64-bit handle (via the ``handle`` property).
39 .. versionadded:: 1.1.0
40 """
42 def __init__(self, *args, **kwargs):
43 raise RuntimeError( 1h
44 "SurfaceObject cannot be instantiated directly. "
45 "Use Device.create_surface_object()."
46 )
48 @property
49 def handle(self):
50 """The underlying ``CUsurfObject`` as an integer (64-bit kernel arg)."""
51 return as_intptr(self._handle) 1abc
53 @property
54 def resource(self):
55 """The :class:`ResourceDescriptor` this surface was built from."""
56 return self._source_ref 1a
58 @property
59 def device(self):
60 from cuda.core._device import Device
61 return Device(self._device_id)
63 cpdef close(self):
64 """Release this object's reference to the underlying ``CUsurfObject``.
66 Destruction (``cuSurfObjectDestroy``) and release of the backing array
67 happen via the handle's deleter when the last reference is dropped.
68 Idempotent.
69 """
70 self._handle.reset() 1abc
71 self._source_ref = None 1abc
73 def __enter__(self):
74 return self
76 def __exit__(self, exc_type, exc, tb):
77 self.close()
79 def __repr__(self):
80 return f"SurfaceObject(handle=0x{as_intptr(self._handle):x})"
83def _create_surface_object(resource):
84 """Create a :class:`SurfaceObject` on the current device.
86 Backs :meth:`cuda.core.Device.create_surface_object`. ``resource`` must be a
87 :class:`ResourceDescriptor` wrapping an :class:`OpaqueArray` allocated with
88 ``is_surface_load_store=True``; linear/pitch2d resources are not valid
89 surface backings.
90 """
91 if not isinstance(resource, ResourceDescriptor): 1abefgc
92 raise TypeError(
93 f"resource must be a ResourceDescriptor, got "
94 f"{type(resource).__name__}"
95 )
96 if resource.kind != "array": 1abefgc
97 raise ValueError( 1ef
98 f"SurfaceObject requires an array-backed ResourceDescriptor, " 1ef
99 f"got kind={resource.kind!r}" 1ef
100 )
102 cdef OpaqueArray arr = <OpaqueArray>resource.source 1abgc
103 if not arr.is_surface_load_store: 1abgc
104 raise ValueError( 1g
105 "OpaqueArray must be created with is_surface_load_store=True to be "
106 "bound as a SurfaceObject"
107 )
109 cdef cydriver.CUDA_RESOURCE_DESC res_desc
110 memset(&res_desc, 0, sizeof(res_desc)) 1abc
111 res_desc.resType = cydriver.CU_RESOURCE_TYPE_ARRAY 1abc
112 res_desc.res.array.hArray = as_cu(arr._handle) 1abc
114 cdef SurfObjectHandle h = create_surf_object_handle(res_desc, arr._handle) 1abc
115 if not h: 1dabc
116 HANDLE_RETURN(get_last_error())
118 cdef SurfaceObject self = SurfaceObject.__new__(SurfaceObject) 1abc
119 self._handle = h 1abc
120 self._source_ref = resource 1abc
121 self._device_id = _get_current_device_id() 1abc
122 return self 1abc