Coverage for cuda/core/texture/_surface.pyx: 77.50%
40 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-03 02:41 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-03 02:41 +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, OpaqueArray_check_open
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( 1ei
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 is_closed(self) -> bool:
55 """Whether this surface object has been closed."""
56 return self._handle.get() == NULL 1d
58 @property
59 def resource(self):
60 """The :class:`ResourceDescriptor` this surface was built from."""
61 return self._source_ref 1a
63 @property
64 def device(self):
65 from cuda.core._device import Device
66 return Device(self._device_id)
68 cpdef close(self):
69 """Release this object's reference to the underlying ``CUsurfObject``.
71 Destruction (``cuSurfObjectDestroy``) and release of the backing array
72 happen via the handle's deleter when the last reference is dropped.
73 Idempotent.
74 """
75 self._handle.reset() 1abdc
76 self._source_ref = None 1abdc
78 def __enter__(self):
79 return self
81 def __exit__(self, exc_type, exc, tb):
82 self.close()
84 def __repr__(self):
85 return f"SurfaceObject(handle=0x{as_intptr(self._handle):x})"
88def _create_surface_object(resource):
89 """Create a :class:`SurfaceObject` on the current device.
91 Backs :meth:`cuda.core.Device.create_surface_object`. ``resource`` must be a
92 :class:`ResourceDescriptor` wrapping an :class:`OpaqueArray` allocated with
93 ``is_surface_load_store=True``; linear/pitch2d resources are not valid
94 surface backings.
95 """
96 if not isinstance(resource, ResourceDescriptor): 1abghfdc
97 raise TypeError(
98 f"resource must be a ResourceDescriptor, got "
99 f"{type(resource).__name__}"
100 )
101 if resource.kind != "array": 1abghfdc
102 raise ValueError( 1gh
103 f"SurfaceObject requires an array-backed ResourceDescriptor, " 1gh
104 f"got kind={resource.kind!r}" 1gh
105 )
107 cdef OpaqueArray arr = <OpaqueArray>resource.source 1abfdc
108 OpaqueArray_check_open(arr) 1abfdc
109 if not arr.is_surface_load_store: 1abfdc
110 raise ValueError( 1f
111 "OpaqueArray must be created with is_surface_load_store=True to be "
112 "bound as a SurfaceObject"
113 )
115 cdef cydriver.CUDA_RESOURCE_DESC res_desc
116 memset(&res_desc, 0, sizeof(res_desc)) 1abdc
117 res_desc.resType = cydriver.CU_RESOURCE_TYPE_ARRAY 1abdc
118 res_desc.res.array.hArray = as_cu(arr._handle) 1abdc
120 cdef SurfObjectHandle h = create_surf_object_handle(res_desc, arr._handle) 1abdc
121 if not h: 1abdc
122 HANDLE_RETURN(get_last_error())
124 cdef SurfaceObject self = SurfaceObject.__new__(SurfaceObject) 1abdc
125 self._handle = h 1abdc
126 self._source_ref = resource 1abdc
127 self._device_id = _get_current_device_id() 1abdc
128 return self 1abdc