1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! Provides the Cuda API with its memory/buffer functionality.

use super::ffi::*;
use super::{Error, API};
use crate::frameworks::cuda::Memory;
use crate::frameworks::native::flatbox::FlatBox;

impl API {
    /// Allocates memory on the Cuda device.
    ///
    /// Allocates bytesize bytes of linear memory on the device. The allocated memory is suitably
    /// aligned for any kind of variable. The memory is not cleared.
    /// Returns a memory id for the created buffer, which can now be writen to.
    pub fn mem_alloc(bytesize: size_t) -> Result<Memory, Error> {
        Ok(Memory::from_c(unsafe { API::ffi_mem_alloc(bytesize) }?))
    }

    /// Releases allocated memory from the Cuda device.
    pub fn mem_free(memory: CUdeviceptr) -> Result<(), Error> {
        unsafe { API::ffi_mem_free(memory) }
    }

    /// Copies memory from the Host to the Cuda device.
    pub fn mem_cpy_h_to_d(host_mem: &FlatBox, device_mem: &mut Memory) -> Result<(), Error> {
        unsafe {
            API::ffi_mem_cpy_h_to_d(
                *device_mem.id_c(),
                host_mem.as_slice().as_ptr(),
                host_mem.byte_size(),
            )
        }
    }

    /// Copies memory from the Cuda device to the Host.
    pub fn mem_cpy_d_to_h(device_mem: &Memory, host_mem: &mut FlatBox) -> Result<(), Error> {
        unsafe {
            API::ffi_mem_cpy_d_to_h(
                host_mem.as_mut_slice().as_mut_ptr(),
                *device_mem.id_c(),
                host_mem.byte_size(),
            )
        }
    }

    unsafe fn ffi_mem_alloc(bytesize: size_t) -> Result<CUdeviceptr, Error> {
        let mut memory_id: CUdeviceptr = 0;
        match cuMemAlloc_v2(&mut memory_id, bytesize) {
            CUresult::CUDA_SUCCESS => Ok(memory_id),
            CUresult::CUDA_ERROR_DEINITIALIZED => {
                Err(Error::Deinitialized("CUDA got deinitialized."))
            }
            CUresult::CUDA_ERROR_NOT_INITIALIZED => {
                Err(Error::NotInitialized("CUDA is not initialized."))
            }
            CUresult::CUDA_ERROR_INVALID_CONTEXT => {
                Err(Error::InvalidContext("No valid context available."))
            }
            CUresult::CUDA_ERROR_INVALID_VALUE => {
                Err(Error::InvalidValue("Invalid value provided."))
            }
            CUresult::CUDA_ERROR_OUT_OF_MEMORY => {
                Err(Error::OutOfMemory("Device is out of memory."))
            }
            status => Err(Error::Unknown(
                "Unable to allocate memory.",
                status as i32 as u64,
            )),
        }
    }

    unsafe fn ffi_mem_free(dptr: CUdeviceptr) -> Result<(), Error> {
        match cuMemFree_v2(dptr) {
            CUresult::CUDA_SUCCESS => Ok(()),
            CUresult::CUDA_ERROR_DEINITIALIZED => {
                Err(Error::Deinitialized("CUDA got deinitialized."))
            }
            CUresult::CUDA_ERROR_NOT_INITIALIZED => {
                Err(Error::NotInitialized("CUDA is not initialized."))
            }
            CUresult::CUDA_ERROR_INVALID_CONTEXT => {
                Err(Error::InvalidContext("No valid context available."))
            }
            CUresult::CUDA_ERROR_INVALID_VALUE => {
                Err(Error::InvalidValue("Invalid value provided."))
            }
            status => Err(Error::Unknown(
                "Unable to free memory.",
                status as i32 as u64,
            )),
        }
    }

    unsafe fn ffi_mem_cpy_h_to_d(
        dst_device: CUdeviceptr,
        src_host: *const ::libc::c_void,
        byte_count: size_t,
    ) -> Result<(), Error> {
        match cuMemcpyHtoD_v2(dst_device, src_host, byte_count) {
            CUresult::CUDA_SUCCESS => Ok(()),
            CUresult::CUDA_ERROR_DEINITIALIZED => {
                Err(Error::Deinitialized("CUDA got deinitialized."))
            }
            CUresult::CUDA_ERROR_NOT_INITIALIZED => {
                Err(Error::NotInitialized("CUDA is not initialized."))
            }
            CUresult::CUDA_ERROR_INVALID_CONTEXT => {
                Err(Error::InvalidContext("No valid context available."))
            }
            CUresult::CUDA_ERROR_INVALID_VALUE => {
                Err(Error::InvalidValue("Invalid value provided."))
            }
            status => Err(Error::Unknown(
                "Unable to copy memory from host to device.",
                status as i32 as u64,
            )),
        }
    }

    unsafe fn ffi_mem_cpy_d_to_h(
        dst_host: *mut ::libc::c_void,
        src_device: CUdeviceptr,
        byte_count: size_t,
    ) -> Result<(), Error> {
        let status = cuMemcpyDtoH_v2(dst_host, src_device, byte_count);
        match status {
            CUresult::CUDA_SUCCESS => Ok(()),
            CUresult::CUDA_ERROR_DEINITIALIZED => {
                Err(Error::Deinitialized("CUDA got deinitialized."))
            }
            CUresult::CUDA_ERROR_NOT_INITIALIZED => {
                Err(Error::NotInitialized("CUDA is not initialized."))
            }
            CUresult::CUDA_ERROR_INVALID_CONTEXT => {
                Err(Error::InvalidContext("No valid context available."))
            }
            CUresult::CUDA_ERROR_INVALID_VALUE => {
                Err(Error::InvalidValue("Invalid value provided."))
            }
            status => Err(Error::Unknown(
                "Unable to copy memory from device to host.",
                status as i32 as u64,
            )),
        }
    }
}