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

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

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

89 """Create a :class:`SurfaceObject` on the current 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 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 ) 

114  

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

119  

120 cdef SurfObjectHandle h = create_surf_object_handle(res_desc, arr._handle) 1abdc

121 if not h: 1abdc

122 HANDLE_RETURN(get_last_error()) 

123  

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