Coverage for cuda/core/texture/_surface.pyx: 72.34%
47 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-10 02:27 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-10 02:27 +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._context cimport Context
11from cuda.core.texture._array cimport OpaqueArray, OpaqueArray_check_open
12from cuda.core._resource_handles cimport (
13 ContextHandle,
14 SurfObjectHandle,
15 as_cu,
16 as_intptr,
17 create_surf_object_handle,
18 get_array_context,
19 get_last_error,
20)
21from cuda.core.texture._texture import ResourceDescriptor
22from cuda.core._utils.cuda_utils cimport HANDLE_RETURN
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, Context ctx, int device_id):
89 """Create a :class:`SurfaceObject` on the specified 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 arr._device_id != device_id: 1abfdc
110 raise ValueError(
111 f"resource belongs to device {arr._device_id}, "
112 f"but surface creation was requested on device {device_id}"
113 )
114 cdef ContextHandle resource_context = get_array_context(arr._handle) 1abfdc
115 if resource_context and as_cu(resource_context) != as_cu(ctx._h_context): 1eabfdc
116 raise ValueError("resource is not compatible with this Device object")
117 if not arr.is_surface_load_store: 1abfdc
118 raise ValueError( 1f
119 "OpaqueArray must be created with is_surface_load_store=True to be "
120 "bound as a SurfaceObject"
121 )
123 cdef cydriver.CUDA_RESOURCE_DESC res_desc
124 memset(&res_desc, 0, sizeof(res_desc)) 1abdc
125 res_desc.resType = cydriver.CU_RESOURCE_TYPE_ARRAY 1abdc
126 res_desc.res.array.hArray = as_cu(arr._handle) 1abdc
128 cdef SurfObjectHandle h = create_surf_object_handle( 1abdc
129 ctx._h_context, res_desc, arr._handle)
130 if not h: 1abdc
131 HANDLE_RETURN(get_last_error())
133 cdef SurfaceObject self = SurfaceObject.__new__(SurfaceObject) 1eabdc
134 self._handle = h 1abdc
135 self._source_ref = resource 1abdc
136 self._device_id = device_id 1abdc
137 return self 1abdc