# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

# This module compiles _cpp/resource_handles.cpp into a shared library.
# Consumer modules cimport the functions declared in _resource_handles.pxd.
# Since there is only one copy of the C++ code (in this .so), all static and
# thread-local state is shared correctly across all consumer modules.
#
# The cdef extern from declarations below satisfy the .pxd declarations directly,
# without needing separate wrapper functions.

from cpython.pycapsule cimport PyCapsule_GetName, PyCapsule_GetPointer
from libc.stddef cimport size_t

from cuda.bindings cimport cydriver
from cuda.bindings cimport cynvrtc
from cuda.bindings cimport cynvvm
from cuda.bindings cimport cynvjitlink

import cuda.bindings.cydriver as cydriver
import cuda.bindings.cynvrtc as cynvrtc
import cuda.bindings.cynvvm as cynvvm
import cuda.bindings.cynvjitlink as cynvjitlink

# =============================================================================
# C++ function declarations (non-inline, implemented in resource_handles.cpp)
#
# These declarations satisfy the cdef function declarations in _resource_handles.pxd.
# Consumer modules cimport these functions and calls go through this .so.
# =============================================================================

cdef extern from "_cpp/resource_handles.hpp" namespace "cuda_core":
    # Thread-local error handling
    cydriver.CUresult get_last_error "cuda_core::get_last_error" () noexcept nogil
    cydriver.CUresult peek_last_error "cuda_core::peek_last_error" () noexcept nogil
    void clear_last_error "cuda_core::clear_last_error" () noexcept nogil

    # Context handles
    ContextHandle create_context_handle_ref "cuda_core::create_context_handle_ref" (
        cydriver.CUcontext ctx) except+ nogil
    ContextHandle create_context_handle_from_green_ctx "cuda_core::create_context_handle_from_green_ctx" (
        const GreenCtxHandle& h_green_ctx) except+ nogil
    GreenCtxHandle get_context_green_ctx "cuda_core::get_context_green_ctx" (
        const ContextHandle& h) noexcept nogil
    GreenCtxHandle create_green_ctx_handle "cuda_core::create_green_ctx_handle" (
        cydriver.CUdevResource* resources, unsigned int nbResources,
        cydriver.CUdevice dev, unsigned int flags) except+ nogil
    GreenCtxHandle create_green_ctx_handle_ref "cuda_core::create_green_ctx_handle_ref" (
        cydriver.CUgreenCtx ctx) except+ nogil
    ContextHandle get_primary_context "cuda_core::get_primary_context" (
        int device_id) except+ nogil
    ContextHandle get_current_context "cuda_core::get_current_context" () except+ nogil

    # Stream handles
    StreamHandle create_stream_handle "cuda_core::create_stream_handle" (
        const ContextHandle& h_ctx, unsigned int flags, int priority) except+ nogil
    StreamHandle create_stream_handle_ref "cuda_core::create_stream_handle_ref" (
        cydriver.CUstream stream) except+ nogil
    StreamHandle create_stream_handle_with_owner "cuda_core::create_stream_handle_with_owner" (
        cydriver.CUstream stream, object owner) except+ nogil
    void py_object_user_object_destroy "cuda_core::py_object_user_object_destroy" (
        void* py_object) noexcept nogil
    void initialize_deferred_cleanup "cuda_core::initialize_deferred_cleanup" () except+
    void retry_deferred_cleanup "cuda_core::retry_deferred_cleanup" () noexcept
    ContextHandle get_stream_context "cuda_core::get_stream_context" (
        const StreamHandle& h) noexcept nogil
    StreamHandle get_legacy_stream "cuda_core::get_legacy_stream" () except+ nogil
    StreamHandle get_per_thread_stream "cuda_core::get_per_thread_stream" () except+ nogil

    # Event handles (note: _create_event_handle* are internal due to C++ overloading)
    EventHandle create_event_handle "cuda_core::create_event_handle" (
        const ContextHandle& h_ctx, unsigned int flags,
        bint timing_enabled, bint is_blocking_sync,
        bint ipc_enabled, int device_id) except+ nogil
    EventHandle create_event_handle_noctx "cuda_core::create_event_handle_noctx" (
        unsigned int flags) except+ nogil
    EventHandle create_event_handle_ref "cuda_core::create_event_handle_ref" (
        cydriver.CUevent event) except+ nogil
    EventHandle create_event_handle_ipc "cuda_core::create_event_handle_ipc" (
        const cydriver.CUipcEventHandle& ipc_handle, bint is_blocking_sync) except+ nogil

    # Event metadata getters
    bint get_event_timing_enabled "cuda_core::get_event_timing_enabled" (
        const EventHandle& h) noexcept nogil
    bint get_event_is_blocking_sync "cuda_core::get_event_is_blocking_sync" (
        const EventHandle& h) noexcept nogil
    bint get_event_ipc_enabled "cuda_core::get_event_ipc_enabled" (
        const EventHandle& h) noexcept nogil
    int get_event_device_id "cuda_core::get_event_device_id" (
        const EventHandle& h) noexcept nogil
    ContextHandle get_event_context "cuda_core::get_event_context" (
        const EventHandle& h) noexcept nogil

    # Memory pool handles
    MemoryPoolHandle create_mempool_handle "cuda_core::create_mempool_handle" (
        const cydriver.CUmemPoolProps& props) except+ nogil
    MemoryPoolHandle create_mempool_handle_ref "cuda_core::create_mempool_handle_ref" (
        cydriver.CUmemoryPool pool) except+ nogil
    MemoryPoolHandle get_device_mempool "cuda_core::get_device_mempool" (
        int device_id) except+ nogil
    MemoryPoolHandle create_mempool_handle_ipc "cuda_core::create_mempool_handle_ipc" (
        int fd, cydriver.CUmemAllocationHandleType handle_type) except+ nogil

    # Device pointer handles
    DevicePtrHandle deviceptr_alloc_from_pool "cuda_core::deviceptr_alloc_from_pool" (
        size_t size, const MemoryPoolHandle& h_pool, const StreamHandle& h_stream) except+ nogil
    DevicePtrHandle deviceptr_alloc_async "cuda_core::deviceptr_alloc_async" (
        size_t size, const StreamHandle& h_stream) except+ nogil
    DevicePtrHandle deviceptr_alloc "cuda_core::deviceptr_alloc" (size_t size) except+ nogil
    DevicePtrHandle deviceptr_alloc_host "cuda_core::deviceptr_alloc_host" (size_t size) except+ nogil
    DevicePtrHandle deviceptr_create_ref "cuda_core::deviceptr_create_ref" (
        cydriver.CUdeviceptr ptr) except+ nogil
    DevicePtrHandle deviceptr_create_with_owner "cuda_core::deviceptr_create_with_owner" (
        cydriver.CUdeviceptr ptr, object owner) except+ nogil
    DevicePtrHandle deviceptr_create_mapped_graphics "cuda_core::deviceptr_create_mapped_graphics" (
        cydriver.CUdeviceptr ptr,
        const GraphicsResourceHandle& h_resource,
        const StreamHandle& h_stream) except+ nogil

    # MR deallocation callback
    void register_mr_dealloc_callback "cuda_core::register_mr_dealloc_callback" (
        MRDeallocCallback cb) noexcept
    DevicePtrHandle deviceptr_create_with_mr "cuda_core::deviceptr_create_with_mr" (
        cydriver.CUdeviceptr ptr, size_t size, object mr) except+ nogil

    DevicePtrHandle deviceptr_import_ipc "cuda_core::deviceptr_import_ipc" (
        const MemoryPoolHandle& h_pool, const void* export_data, const StreamHandle& h_stream) except+ nogil
    StreamHandle deallocation_stream "cuda_core::deallocation_stream" (
        const DevicePtrHandle& h) noexcept nogil
    void set_deallocation_stream "cuda_core::set_deallocation_stream" (
        const DevicePtrHandle& h, const StreamHandle& h_stream) noexcept nogil

    # Library handles
    LibraryHandle create_library_handle_from_file "cuda_core::create_library_handle_from_file" (
        const char* path) except+ nogil
    LibraryHandle create_library_handle_from_data "cuda_core::create_library_handle_from_data" (
        const void* data) except+ nogil
    LibraryHandle create_library_handle_ref "cuda_core::create_library_handle_ref" (
        cydriver.CUlibrary library) except+ nogil

    # Kernel handles
    KernelHandle create_kernel_handle "cuda_core::create_kernel_handle" (
        const LibraryHandle& h_library, const char* name) except+ nogil
    KernelHandle create_kernel_handle_ref "cuda_core::create_kernel_handle_ref" (
        cydriver.CUkernel kernel) except+ nogil
    LibraryHandle get_kernel_library "cuda_core::get_kernel_library" (
        const KernelHandle& h) noexcept nogil

    # Graph handles
    GraphHandle create_graph_handle "cuda_core::create_graph_handle" (
        cydriver.CUgraph graph) except+ nogil
    GraphHandle create_child_graph_handle "cuda_core::create_child_graph_handle" (
        cydriver.CUgraph child_graph, const GraphHandle& h_parent,
        cydriver.CUgraphNode owner_node) except+ nogil

    # Graph node attachments
    OpaqueHandle make_opaque_py "cuda_core::make_opaque_py" (object obj) except+
    OpaqueHandle make_opaque_malloc "cuda_core::make_opaque_malloc" (void* buf) except+
    cydriver.CUresult graph_get_attachment "cuda_core::graph_get_attachment" (
        const GraphHandle& h_graph, cydriver.CUgraphNode node,
        OpaqueHandle* owner0, OpaqueHandle* owner1) except+
    cydriver.CUresult graph_prepare_attachment "cuda_core::graph_prepare_attachment" (
        const GraphHandle& h_graph, OpaqueHandle owner0, OpaqueHandle owner1,
        PreparedAttachment* out_prepared) except+
    cydriver.CUresult graph_commit_attachment "cuda_core::graph_commit_attachment" (
        PreparedAttachment& prepared, cydriver.CUgraphNode node) except+
    cydriver.CUresult graph_clone_attachments "cuda_core::graph_clone_attachments" (
        const GraphHandle& h_clone, const GraphHandle& h_source) except+
    cydriver.CUresult graph_prepare_child_graph_update "cuda_core::graph_prepare_child_graph_update" (
        const GraphHandle& h_parent, const GraphHandle& h_old_child,
        cydriver.CUgraphNode owner_node, const GraphHandle& h_source,
        PreparedChildGraphUpdate* out_prepared) except+
    cydriver.CUresult graph_commit_child_graph_update "cuda_core::graph_commit_child_graph_update" (
        PreparedChildGraphUpdate& prepared, GraphHandle* out_child) except+
    void invalidate_child_graph_state "cuda_core::invalidate_child_graph_state" (
        const GraphHandle& h_parent, cydriver.CUgraphNode owner_node) noexcept

    # Graph exec handles
    GraphExecHandle create_graph_exec_handle "cuda_core::create_graph_exec_handle" (
        const GraphHandle& h_source,
        cydriver.CUDA_GRAPH_INSTANTIATE_PARAMS* params) except+
    cydriver.CUresult graph_exec_update "cuda_core::graph_exec_update" (
        const GraphExecHandle& h_exec,
        const GraphHandle& h_source,
        cydriver.CUgraphExecUpdateResultInfo* result_info) except+
    cydriver.CUresult graph_prepare_exec_attachment "cuda_core::graph_prepare_exec_attachment" (
        const GraphExecHandle& h_exec,
        OpaqueHandle owner0,
        OpaqueHandle owner1,
        PreparedExecAttachment* out_prepared) except+
    void graph_commit_exec_attachment "cuda_core::graph_commit_exec_attachment" (
        PreparedExecAttachment& prepared) noexcept

    # Graph node handles
    GraphNodeHandle create_graph_node_handle "cuda_core::create_graph_node_handle" (
        cydriver.CUgraphNode node, const GraphHandle& h_graph) except+ nogil
    GraphHandle graph_node_get_graph "cuda_core::graph_node_get_graph" (
        const GraphNodeHandle& h) noexcept nogil
    void invalidate_graph_node "cuda_core::invalidate_graph_node" (
        const GraphNodeHandle& h) noexcept nogil

    # Graphics resource handles
    GraphicsResourceHandle create_graphics_resource_handle "cuda_core::create_graphics_resource_handle" (
        cydriver.CUgraphicsResource resource) except+ nogil

    # NVRTC Program handles
    NvrtcProgramHandle create_nvrtc_program_handle "cuda_core::create_nvrtc_program_handle" (
        cynvrtc.nvrtcProgram prog) except+ nogil
    NvrtcProgramHandle create_nvrtc_program_handle_ref "cuda_core::create_nvrtc_program_handle_ref" (
        cynvrtc.nvrtcProgram prog) except+ nogil

    # NVVM Program handles
    NvvmProgramHandle create_nvvm_program_handle "cuda_core::create_nvvm_program_handle" (
        cynvvm.nvvmProgram prog) except+ nogil
    NvvmProgramHandle create_nvvm_program_handle_ref "cuda_core::create_nvvm_program_handle_ref" (
        cynvvm.nvvmProgram prog) except+ nogil

    # nvJitLink handles
    NvJitLinkHandle create_nvjitlink_handle "cuda_core::create_nvjitlink_handle" (
        cynvjitlink.nvJitLinkHandle handle) except+ nogil
    NvJitLinkHandle create_nvjitlink_handle_ref "cuda_core::create_nvjitlink_handle_ref" (
        cynvjitlink.nvJitLinkHandle handle) except+ nogil

    # cuLink handles
    CuLinkHandle create_culink_handle "cuda_core::create_culink_handle" (
        cydriver.CUlinkState state) except+ nogil
    CuLinkHandle create_culink_handle_ref "cuda_core::create_culink_handle_ref" (
        cydriver.CUlinkState state) except+ nogil

    # File descriptor handles
    FileDescriptorHandle create_fd_handle "cuda_core::create_fd_handle" (
        int fd) except+ nogil
    FileDescriptorHandle create_fd_handle_ref "cuda_core::create_fd_handle_ref" (
        int fd) except+ nogil

    # SM resource split (13.1+ wrapper — avoids direct cydriver cimport)
    # groupParams is void* to avoid referencing CU_DEV_SM_RESOURCE_GROUP_PARAMS
    # (which doesn't exist in cuda-bindings 13.0 .pxd). The C++ side casts it.
    cydriver.CUresult sm_resource_split "cuda_core::sm_resource_split" (
        cydriver.CUdevResource* result, unsigned int nbGroups,
        const cydriver.CUdevResource* input, cydriver.CUdevResource* remainder,
        unsigned int flags, void* groupParams) nogil
    bint has_sm_resource_split "cuda_core::has_sm_resource_split" () noexcept nogil

    # Array / mipmapped-array / texture / surface handles (PR #467)
    OpaqueArrayHandle create_array_handle "cuda_core::create_array_handle" (
        const cydriver.CUDA_ARRAY3D_DESCRIPTOR& desc) except+ nogil
    OpaqueArrayHandle create_array_handle_ref "cuda_core::create_array_handle_ref" (
        cydriver.CUarray arr) except+ nogil
    OpaqueArrayHandle create_array_handle_owning "cuda_core::create_array_handle_owning" (
        cydriver.CUarray arr) except+ nogil
    OpaqueArrayHandle create_array_level_handle "cuda_core::create_array_level_handle" (
        const MipmappedArrayHandle& h_mip, unsigned int level) except+ nogil
    MipmappedArrayHandle create_mipmapped_array_handle "cuda_core::create_mipmapped_array_handle" (
        const cydriver.CUDA_ARRAY3D_DESCRIPTOR& desc, unsigned int num_levels) except+ nogil
    TexObjectHandle create_tex_object_handle_array "cuda_core::create_tex_object_handle_array" (
        const cydriver.CUDA_RESOURCE_DESC& res, const cydriver.CUDA_TEXTURE_DESC& tex,
        const OpaqueArrayHandle& h_backing) except+ nogil
    TexObjectHandle create_tex_object_handle_mipmap "cuda_core::create_tex_object_handle_mipmap" (
        const cydriver.CUDA_RESOURCE_DESC& res, const cydriver.CUDA_TEXTURE_DESC& tex,
        const MipmappedArrayHandle& h_backing) except+ nogil
    TexObjectHandle create_tex_object_handle_linear "cuda_core::create_tex_object_handle_linear" (
        const cydriver.CUDA_RESOURCE_DESC& res, const cydriver.CUDA_TEXTURE_DESC& tex,
        const DevicePtrHandle& h_backing) except+ nogil
    SurfObjectHandle create_surf_object_handle "cuda_core::create_surf_object_handle" (
        const cydriver.CUDA_RESOURCE_DESC& res, const OpaqueArrayHandle& h_backing) except+ nogil


# =============================================================================
# CUDA Driver API capsule
#
# This provides resolved CUDA driver function pointers to the C++ code.
# =============================================================================

cdef const char* _CUDA_DRIVER_API_V1_NAME = b"cuda.core._resource_handles._CUDA_DRIVER_API_V1"


# =============================================================================
# CUDA driver function pointer initialization
#
# The C++ code declares extern function pointers (p_cuXxx) that need to be
# populated before any handle creation functions are called. We extract these
# from cuda.bindings.cydriver.__pyx_capi__ at module import time.
#
# The Cython string substitution (e.g., "reinterpret_cast<void*&>(...)")
# allows us to assign void* values to typed function pointer variables.
# =============================================================================

# Declare extern variables with reinterpret_cast to allow void* assignment
cdef extern from "_cpp/resource_handles.hpp" namespace "cuda_core":
    # Context
    void* p_cuDevicePrimaryCtxRetain "reinterpret_cast<void*&>(cuda_core::p_cuDevicePrimaryCtxRetain)"
    void* p_cuDevicePrimaryCtxRelease "reinterpret_cast<void*&>(cuda_core::p_cuDevicePrimaryCtxRelease)"
    void* p_cuCtxGetCurrent "reinterpret_cast<void*&>(cuda_core::p_cuCtxGetCurrent)"
    void* p_cuGreenCtxCreate "reinterpret_cast<void*&>(cuda_core::p_cuGreenCtxCreate)"
    void* p_cuGreenCtxDestroy "reinterpret_cast<void*&>(cuda_core::p_cuGreenCtxDestroy)"
    void* p_cuCtxFromGreenCtx "reinterpret_cast<void*&>(cuda_core::p_cuCtxFromGreenCtx)"
    void* p_cuDevResourceGenerateDesc "reinterpret_cast<void*&>(cuda_core::p_cuDevResourceGenerateDesc)"
    void* p_cuGreenCtxStreamCreate "reinterpret_cast<void*&>(cuda_core::p_cuGreenCtxStreamCreate)"

    # Stream
    void* p_cuStreamCreateWithPriority "reinterpret_cast<void*&>(cuda_core::p_cuStreamCreateWithPriority)"
    void* p_cuStreamDestroy "reinterpret_cast<void*&>(cuda_core::p_cuStreamDestroy)"

    # Event
    void* p_cuEventCreate "reinterpret_cast<void*&>(cuda_core::p_cuEventCreate)"
    void* p_cuEventDestroy "reinterpret_cast<void*&>(cuda_core::p_cuEventDestroy)"
    void* p_cuIpcOpenEventHandle "reinterpret_cast<void*&>(cuda_core::p_cuIpcOpenEventHandle)"

    # Device
    void* p_cuDeviceGetCount "reinterpret_cast<void*&>(cuda_core::p_cuDeviceGetCount)"

    # Memory pool
    void* p_cuMemPoolSetAccess "reinterpret_cast<void*&>(cuda_core::p_cuMemPoolSetAccess)"
    void* p_cuMemPoolDestroy "reinterpret_cast<void*&>(cuda_core::p_cuMemPoolDestroy)"
    void* p_cuMemPoolCreate "reinterpret_cast<void*&>(cuda_core::p_cuMemPoolCreate)"
    void* p_cuDeviceGetMemPool "reinterpret_cast<void*&>(cuda_core::p_cuDeviceGetMemPool)"
    void* p_cuMemPoolImportFromShareableHandle "reinterpret_cast<void*&>(cuda_core::p_cuMemPoolImportFromShareableHandle)"

    # Memory allocation
    void* p_cuMemAllocFromPoolAsync "reinterpret_cast<void*&>(cuda_core::p_cuMemAllocFromPoolAsync)"
    void* p_cuMemAllocAsync "reinterpret_cast<void*&>(cuda_core::p_cuMemAllocAsync)"
    void* p_cuMemAlloc "reinterpret_cast<void*&>(cuda_core::p_cuMemAlloc)"
    void* p_cuMemAllocHost "reinterpret_cast<void*&>(cuda_core::p_cuMemAllocHost)"

    # Memory deallocation
    void* p_cuMemFreeAsync "reinterpret_cast<void*&>(cuda_core::p_cuMemFreeAsync)"
    void* p_cuMemFree "reinterpret_cast<void*&>(cuda_core::p_cuMemFree)"
    void* p_cuMemFreeHost "reinterpret_cast<void*&>(cuda_core::p_cuMemFreeHost)"

    # IPC
    void* p_cuMemPoolImportPointer "reinterpret_cast<void*&>(cuda_core::p_cuMemPoolImportPointer)"

    # Library
    void* p_cuLibraryLoadFromFile "reinterpret_cast<void*&>(cuda_core::p_cuLibraryLoadFromFile)"
    void* p_cuLibraryLoadData "reinterpret_cast<void*&>(cuda_core::p_cuLibraryLoadData)"
    void* p_cuLibraryUnload "reinterpret_cast<void*&>(cuda_core::p_cuLibraryUnload)"
    void* p_cuLibraryGetKernel "reinterpret_cast<void*&>(cuda_core::p_cuLibraryGetKernel)"

    # Graph
    void* p_cuGraphDestroy "reinterpret_cast<void*&>(cuda_core::p_cuGraphDestroy)"
    void* p_cuGraphInstantiateWithParams "reinterpret_cast<void*&>(cuda_core::p_cuGraphInstantiateWithParams)"
    void* p_cuGraphExecUpdate "reinterpret_cast<void*&>(cuda_core::p_cuGraphExecUpdate)"
    void* p_cuGraphExecDestroy "reinterpret_cast<void*&>(cuda_core::p_cuGraphExecDestroy)"
    void* p_cuUserObjectCreate "reinterpret_cast<void*&>(cuda_core::p_cuUserObjectCreate)"
    void* p_cuUserObjectRelease "reinterpret_cast<void*&>(cuda_core::p_cuUserObjectRelease)"
    void* p_cuGraphRetainUserObject "reinterpret_cast<void*&>(cuda_core::p_cuGraphRetainUserObject)"
    void* p_cuGraphReleaseUserObject "reinterpret_cast<void*&>(cuda_core::p_cuGraphReleaseUserObject)"
    void* p_cuGraphNodeFindInClone "reinterpret_cast<void*&>(cuda_core::p_cuGraphNodeFindInClone)"
    void* p_cuGraphChildGraphNodeGetGraph "reinterpret_cast<void*&>(cuda_core::p_cuGraphChildGraphNodeGetGraph)"

    # Linker
    void* p_cuLinkDestroy "reinterpret_cast<void*&>(cuda_core::p_cuLinkDestroy)"

    # Graphics interop
    void* p_cuGraphicsUnmapResources "reinterpret_cast<void*&>(cuda_core::p_cuGraphicsUnmapResources)"
    void* p_cuGraphicsUnregisterResource "reinterpret_cast<void*&>(cuda_core::p_cuGraphicsUnregisterResource)"

    # Texture / surface / array (PR #467)
    void* p_cuArray3DCreate "reinterpret_cast<void*&>(cuda_core::p_cuArray3DCreate)"
    void* p_cuArrayDestroy "reinterpret_cast<void*&>(cuda_core::p_cuArrayDestroy)"
    void* p_cuMipmappedArrayCreate "reinterpret_cast<void*&>(cuda_core::p_cuMipmappedArrayCreate)"
    void* p_cuMipmappedArrayDestroy "reinterpret_cast<void*&>(cuda_core::p_cuMipmappedArrayDestroy)"
    void* p_cuMipmappedArrayGetLevel "reinterpret_cast<void*&>(cuda_core::p_cuMipmappedArrayGetLevel)"
    void* p_cuTexObjectCreate "reinterpret_cast<void*&>(cuda_core::p_cuTexObjectCreate)"
    void* p_cuTexObjectDestroy "reinterpret_cast<void*&>(cuda_core::p_cuTexObjectDestroy)"
    void* p_cuSurfObjectCreate "reinterpret_cast<void*&>(cuda_core::p_cuSurfObjectCreate)"
    void* p_cuSurfObjectDestroy "reinterpret_cast<void*&>(cuda_core::p_cuSurfObjectDestroy)"

    # SM resource split (13.1+)
    void* p_cuDevSmResourceSplit "reinterpret_cast<void*&>(cuda_core::p_cuDevSmResourceSplit)"

    # NVRTC
    void* p_nvrtcDestroyProgram "reinterpret_cast<void*&>(cuda_core::p_nvrtcDestroyProgram)"

    # NVVM
    void* p_nvvmDestroyProgram "reinterpret_cast<void*&>(cuda_core::p_nvvmDestroyProgram)"

    # nvJitLink
    void* p_nvJitLinkDestroy "reinterpret_cast<void*&>(cuda_core::p_nvJitLinkDestroy)"


# Initialize driver function pointers from cydriver.__pyx_capi__ at module load
cdef void* _get_driver_fn(str name):
    capsule = cydriver.__pyx_capi__[name]
    return PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule))


cdef void* _get_optional_driver_fn(str name):
    try:
        capsule = cydriver.__pyx_capi__[name]
    except KeyError:
        return NULL
    return PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule))


cdef void _init_driver_fn_pointers() noexcept:
    global p_cuDevicePrimaryCtxRetain, p_cuDevicePrimaryCtxRelease, p_cuCtxGetCurrent
    global p_cuGreenCtxCreate, p_cuGreenCtxDestroy, p_cuCtxFromGreenCtx
    global p_cuDevResourceGenerateDesc, p_cuGreenCtxStreamCreate
    global p_cuStreamCreateWithPriority, p_cuStreamDestroy
    global p_cuEventCreate, p_cuEventDestroy, p_cuIpcOpenEventHandle
    global p_cuDeviceGetCount
    global p_cuMemPoolSetAccess, p_cuMemPoolDestroy, p_cuMemPoolCreate
    global p_cuDeviceGetMemPool, p_cuMemPoolImportFromShareableHandle
    global p_cuMemAllocFromPoolAsync, p_cuMemAllocAsync, p_cuMemAlloc, p_cuMemAllocHost
    global p_cuMemFreeAsync, p_cuMemFree, p_cuMemFreeHost
    global p_cuMemPoolImportPointer
    global p_cuLibraryLoadFromFile, p_cuLibraryLoadData, p_cuLibraryUnload, p_cuLibraryGetKernel
    global p_cuGraphDestroy, p_cuGraphInstantiateWithParams
    global p_cuGraphExecUpdate, p_cuGraphExecDestroy
    global p_cuUserObjectCreate, p_cuUserObjectRelease
    global p_cuGraphRetainUserObject, p_cuGraphReleaseUserObject
    global p_cuGraphNodeFindInClone, p_cuGraphChildGraphNodeGetGraph
    global p_cuLinkDestroy
    global p_cuGraphicsUnmapResources, p_cuGraphicsUnregisterResource
    global p_cuDevSmResourceSplit
    global p_cuArray3DCreate, p_cuArrayDestroy
    global p_cuMipmappedArrayCreate, p_cuMipmappedArrayDestroy, p_cuMipmappedArrayGetLevel
    global p_cuTexObjectCreate, p_cuTexObjectDestroy
    global p_cuSurfObjectCreate, p_cuSurfObjectDestroy

    # Context
    p_cuDevicePrimaryCtxRetain = _get_driver_fn("cuDevicePrimaryCtxRetain")
    p_cuDevicePrimaryCtxRelease = _get_driver_fn("cuDevicePrimaryCtxRelease")
    p_cuCtxGetCurrent = _get_driver_fn("cuCtxGetCurrent")
    p_cuGreenCtxCreate = _get_optional_driver_fn("cuGreenCtxCreate")
    p_cuGreenCtxDestroy = _get_optional_driver_fn("cuGreenCtxDestroy")
    p_cuCtxFromGreenCtx = _get_optional_driver_fn("cuCtxFromGreenCtx")
    p_cuDevResourceGenerateDesc = _get_optional_driver_fn("cuDevResourceGenerateDesc")
    p_cuGreenCtxStreamCreate = _get_optional_driver_fn("cuGreenCtxStreamCreate")

    # Stream
    p_cuStreamCreateWithPriority = _get_driver_fn("cuStreamCreateWithPriority")
    p_cuStreamDestroy = _get_driver_fn("cuStreamDestroy")

    # Event
    p_cuEventCreate = _get_driver_fn("cuEventCreate")
    p_cuEventDestroy = _get_driver_fn("cuEventDestroy")
    p_cuIpcOpenEventHandle = _get_driver_fn("cuIpcOpenEventHandle")

    # Device
    p_cuDeviceGetCount = _get_driver_fn("cuDeviceGetCount")

    # Memory pool
    p_cuMemPoolSetAccess = _get_driver_fn("cuMemPoolSetAccess")
    p_cuMemPoolDestroy = _get_driver_fn("cuMemPoolDestroy")
    p_cuMemPoolCreate = _get_driver_fn("cuMemPoolCreate")
    p_cuDeviceGetMemPool = _get_driver_fn("cuDeviceGetMemPool")
    p_cuMemPoolImportFromShareableHandle = _get_driver_fn("cuMemPoolImportFromShareableHandle")

    # Memory allocation
    p_cuMemAllocFromPoolAsync = _get_driver_fn("cuMemAllocFromPoolAsync")
    p_cuMemAllocAsync = _get_driver_fn("cuMemAllocAsync")
    p_cuMemAlloc = _get_driver_fn("cuMemAlloc")
    p_cuMemAllocHost = _get_driver_fn("cuMemAllocHost")

    # Memory deallocation
    p_cuMemFreeAsync = _get_driver_fn("cuMemFreeAsync")
    p_cuMemFree = _get_driver_fn("cuMemFree")
    p_cuMemFreeHost = _get_driver_fn("cuMemFreeHost")

    # IPC
    p_cuMemPoolImportPointer = _get_driver_fn("cuMemPoolImportPointer")

    # Library
    p_cuLibraryLoadFromFile = _get_driver_fn("cuLibraryLoadFromFile")
    p_cuLibraryLoadData = _get_driver_fn("cuLibraryLoadData")
    p_cuLibraryUnload = _get_driver_fn("cuLibraryUnload")
    p_cuLibraryGetKernel = _get_driver_fn("cuLibraryGetKernel")

    # Graph
    p_cuGraphDestroy = _get_driver_fn("cuGraphDestroy")
    p_cuGraphInstantiateWithParams = _get_driver_fn("cuGraphInstantiateWithParams")
    p_cuGraphExecUpdate = _get_driver_fn("cuGraphExecUpdate")
    p_cuGraphExecDestroy = _get_driver_fn("cuGraphExecDestroy")
    p_cuUserObjectCreate = _get_driver_fn("cuUserObjectCreate")
    p_cuUserObjectRelease = _get_driver_fn("cuUserObjectRelease")
    p_cuGraphRetainUserObject = _get_driver_fn("cuGraphRetainUserObject")
    p_cuGraphReleaseUserObject = _get_driver_fn("cuGraphReleaseUserObject")
    p_cuGraphNodeFindInClone = _get_driver_fn("cuGraphNodeFindInClone")
    p_cuGraphChildGraphNodeGetGraph = _get_driver_fn("cuGraphChildGraphNodeGetGraph")

    # Linker
    p_cuLinkDestroy = _get_driver_fn("cuLinkDestroy")

    # Graphics interop
    p_cuGraphicsUnmapResources = _get_driver_fn("cuGraphicsUnmapResources")
    p_cuGraphicsUnregisterResource = _get_driver_fn("cuGraphicsUnregisterResource")

    # Texture / surface / array (PR #467)
    p_cuArray3DCreate = _get_driver_fn("cuArray3DCreate")
    p_cuArrayDestroy = _get_driver_fn("cuArrayDestroy")
    p_cuMipmappedArrayCreate = _get_driver_fn("cuMipmappedArrayCreate")
    p_cuMipmappedArrayDestroy = _get_driver_fn("cuMipmappedArrayDestroy")
    p_cuMipmappedArrayGetLevel = _get_driver_fn("cuMipmappedArrayGetLevel")
    p_cuTexObjectCreate = _get_driver_fn("cuTexObjectCreate")
    p_cuTexObjectDestroy = _get_driver_fn("cuTexObjectDestroy")
    p_cuSurfObjectCreate = _get_driver_fn("cuSurfObjectCreate")
    p_cuSurfObjectDestroy = _get_driver_fn("cuSurfObjectDestroy")

    # SM resource split (13.1+ — may not exist in older cuda-bindings)
    p_cuDevSmResourceSplit = _get_optional_driver_fn("cuDevSmResourceSplit")

_init_driver_fn_pointers()
initialize_deferred_cleanup()

# =============================================================================
# NVRTC function pointer initialization
# =============================================================================

cdef void* _get_nvrtc_fn(str name):
    capsule = cynvrtc.__pyx_capi__[name]
    return PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule))

cdef void _init_nvrtc_fn_pointers() noexcept:
    global p_nvrtcDestroyProgram
    p_nvrtcDestroyProgram = _get_nvrtc_fn("nvrtcDestroyProgram")

_init_nvrtc_fn_pointers()

# =============================================================================
# NVVM function pointer initialization
#
# NVVM may not be available at runtime, so we handle missing function pointers
# gracefully. The C++ deleter checks for null before calling.
# =============================================================================

cdef void* _get_nvvm_fn(str name):
    capsule = cynvvm.__pyx_capi__[name]
    return PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule))

cdef void _init_nvvm_fn_pointers() noexcept:
    global p_nvvmDestroyProgram
    p_nvvmDestroyProgram = _get_nvvm_fn("nvvmDestroyProgram")

_init_nvvm_fn_pointers()

# =============================================================================
# nvJitLink function pointer initialization
#
# nvJitLink may not be available at runtime, so we handle missing function
# pointers gracefully. The C++ deleter checks for null before calling.
# =============================================================================

cdef void* _get_nvjitlink_fn(str name):
    capsule = cynvjitlink.__pyx_capi__[name]
    return PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule))

cdef void _init_nvjitlink_fn_pointers() noexcept:
    global p_nvJitLinkDestroy
    p_nvJitLinkDestroy = _get_nvjitlink_fn("nvJitLinkDestroy")

_init_nvjitlink_fn_pointers()
