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

1# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 

2# 

3# SPDX-License-Identifier: Apache-2.0 

4  

5from __future__ import annotations 

6  

7from libc.string cimport memset 

8  

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 

23  

24  

25cdef class SurfaceObject: 

26 """A bindless surface handle for kernel-side typed load/store. 

27  

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. 

31  

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. 

35  

36 Construct via :meth:`cuda.core.Device.create_surface_object`. Passes to 

37 kernels as a 64-bit handle (via the ``handle`` property). 

38  

39 .. versionadded:: 1.1.0 

40 """ 

41  

42 def __init__(self, *args, **kwargs): 

43 raise RuntimeError( 1ei

44 "SurfaceObject cannot be instantiated directly. " 

45 "Use Device.create_surface_object()." 

46 ) 

47  

48 @property 

49 def handle(self): 

50 """The underlying ``CUsurfObject`` as an integer (64-bit kernel arg).""" 

51 return as_intptr(self._handle) 1abc

52  

53 @property 

54 def is_closed(self) -> bool: 

55 """Whether this surface object has been closed.""" 

56 return self._handle.get() == NULL 1d

57  

58 @property 

59 def resource(self): 

60 """The :class:`ResourceDescriptor` this surface was built from.""" 

61 return self._source_ref 1a

62  

63 @property 

64 def device(self): 

65 from cuda.core._device import Device 

66 return Device(self._device_id) 

67  

68 cpdef close(self): 

69 """Release this object's reference to the underlying ``CUsurfObject``. 

70  

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

77  

78 def __enter__(self): 

79 return self 

80  

81 def __exit__(self, exc_type, exc, tb): 

82 self.close() 

83  

84 def __repr__(self): 

85 return f"SurfaceObject(handle=0x{as_intptr(self._handle):x})" 

86  

87  

88def _create_surface_object(resource, Context ctx, int device_id): 

89 """Create a :class:`SurfaceObject` on the specified device. 

90  

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 ) 

106  

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 ) 

122  

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

127  

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()) 

132  

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