use super::defines::AfError;
use super::error::HANDLE_ERROR;
use super::util::{dim_t, free_host, void_ptr};
use libc::{c_char, c_int, size_t};
use std::borrow::Cow;
use std::ffi::{CStr, CString};
extern "C" {
fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int;
fn af_get_revision() -> *const c_char;
fn af_info() -> c_int;
fn af_info_string(str: *mut *mut c_char, verbose: bool) -> c_int;
fn af_device_info(
d_name: *mut c_char,
d_platform: *mut c_char,
d_toolkit: *mut c_char,
d_compute: *mut c_char,
) -> c_int;
fn af_init() -> c_int;
fn af_get_device_count(nDevices: *mut c_int) -> c_int;
fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int;
fn af_set_device(device: c_int) -> c_int;
fn af_get_device(device: *mut c_int) -> c_int;
fn af_device_mem_info(
alloc_bytes: *mut size_t,
alloc_buffers: *mut size_t,
lock_bytes: *mut size_t,
lock_buffers: *mut size_t,
) -> c_int;
fn af_print_mem_info(msg: *const c_char, device_id: c_int) -> c_int;
fn af_set_mem_step_size(step_bytes: size_t) -> c_int;
fn af_get_mem_step_size(step_bytes: *mut size_t) -> c_int;
fn af_device_gc() -> c_int;
fn af_sync(device: c_int) -> c_int;
fn af_alloc_pinned(non_pagable_ptr: *mut void_ptr, bytes: dim_t) -> c_int;
fn af_free_pinned(non_pagable_ptr: void_ptr) -> c_int;
fn af_get_half_support(available: *mut c_int, device: c_int) -> c_int;
}
pub fn get_version() -> (i32, i32, i32) {
unsafe {
let mut maj: i32 = 0;
let mut min: i32 = 0;
let mut pat: i32 = 0;
let err_val = af_get_version(
&mut maj as *mut c_int,
&mut min as *mut c_int,
&mut pat as *mut c_int,
);
HANDLE_ERROR(AfError::from(err_val));
(maj, min, pat)
}
}
pub fn get_revision() -> Cow<'static, str> {
unsafe { CStr::from_ptr(af_get_revision()).to_string_lossy() }
}
pub fn info() {
unsafe {
let err_val = af_info();
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn info_string(verbose: bool) -> String {
let result: String;
unsafe {
let mut tmp: *mut c_char = ::std::ptr::null_mut();
let err_val = af_info_string(&mut tmp, verbose);
HANDLE_ERROR(AfError::from(err_val));
result = CStr::from_ptr(tmp).to_string_lossy().into_owned();
free_host(tmp);
}
result
}
pub fn device_info() -> (String, String, String, String) {
let mut name = [0 as c_char; 64];
let mut platform = [0 as c_char; 10];
let mut toolkit = [0 as c_char; 64];
let mut compute = [0 as c_char; 10];
unsafe {
let err_val = af_device_info(
&mut name[0],
&mut platform[0],
&mut toolkit[0],
&mut compute[0],
);
HANDLE_ERROR(AfError::from(err_val));
(
CStr::from_ptr(name.as_mut_ptr())
.to_string_lossy()
.into_owned(),
CStr::from_ptr(platform.as_mut_ptr())
.to_string_lossy()
.into_owned(),
CStr::from_ptr(toolkit.as_mut_ptr())
.to_string_lossy()
.into_owned(),
CStr::from_ptr(compute.as_mut_ptr())
.to_string_lossy()
.into_owned(),
)
}
}
pub fn init() {
unsafe {
let err_val = af_init();
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn device_count() -> i32 {
unsafe {
let mut temp: i32 = 0;
let err_val = af_get_device_count(&mut temp as *mut c_int);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
pub fn is_double_available(device: i32) -> bool {
unsafe {
let mut temp: i32 = 0;
let err_val = af_get_dbl_support(&mut temp as *mut c_int, device as c_int);
HANDLE_ERROR(AfError::from(err_val));
temp > 0
}
}
pub fn set_device(device: i32) {
unsafe {
let err_val = af_set_device(device as c_int);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn get_device() -> i32 {
unsafe {
let mut temp: i32 = 0;
let err_val = af_get_device(&mut temp as *mut c_int);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
pub fn device_mem_info() -> (usize, usize, usize, usize) {
unsafe {
let mut o0: usize = 0;
let mut o1: usize = 0;
let mut o2: usize = 0;
let mut o3: usize = 0;
let err_val = af_device_mem_info(
&mut o0 as *mut size_t,
&mut o1 as *mut size_t,
&mut o2 as *mut size_t,
&mut o3 as *mut size_t,
);
HANDLE_ERROR(AfError::from(err_val));
(o0, o1, o2, o3)
}
}
pub fn print_mem_info(msg: String, device: i32) {
unsafe {
let cmsg = CString::new(msg.as_bytes());
match cmsg {
Ok(v) => {
let err_val = af_print_mem_info(
v.to_bytes_with_nul().as_ptr() as *const c_char,
device as c_int,
);
HANDLE_ERROR(AfError::from(err_val));
}
Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL),
}
}
}
pub fn set_mem_step_size(step_bytes: usize) {
unsafe {
let err_val = af_set_mem_step_size(step_bytes as size_t);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn get_mem_step_size() -> usize {
unsafe {
let mut temp: usize = 0;
let err_val = af_get_mem_step_size(&mut temp as *mut size_t);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
pub fn device_gc() {
unsafe {
let err_val = af_device_gc();
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn sync(device: i32) {
unsafe {
let err_val = af_sync(device as c_int);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub unsafe fn alloc_pinned(bytes: usize) -> void_ptr {
let mut out: void_ptr = std::ptr::null_mut();
let err_val = af_alloc_pinned(&mut out as *mut void_ptr, bytes as dim_t);
HANDLE_ERROR(AfError::from(err_val));
out
}
pub unsafe fn free_pinned(ptr: void_ptr) {
let err_val = af_free_pinned(ptr);
HANDLE_ERROR(AfError::from(err_val));
}
pub fn is_half_available(device: i32) -> bool {
unsafe {
let mut temp: i32 = 0;
let err_val = af_get_half_support(&mut temp as *mut c_int, device as c_int);
HANDLE_ERROR(AfError::from(err_val));
temp > 0
}
}