2020-11-08 20:28:21 +01:00
extern crate mesa_rust ;
extern crate mesa_rust_util ;
extern crate rusticl_opencl_gen ;
use crate ::api ::icd ::* ;
use crate ::api ::types ::* ;
use crate ::api ::util ::* ;
use crate ::core ::device ::* ;
use crate ::core ::program ::* ;
use self ::mesa_rust ::compiler ::clc ::* ;
use self ::mesa_rust_util ::string ::* ;
use self ::rusticl_opencl_gen ::* ;
use std ::ffi ::CStr ;
use std ::ffi ::CString ;
use std ::os ::raw ::c_char ;
use std ::ptr ;
use std ::slice ;
use std ::sync ::Arc ;
impl CLInfo < cl_program_info > for cl_program {
2022-03-17 12:18:39 +01:00
fn query ( & self , q : cl_program_info , _ : & [ u8 ] ) -> CLResult < Vec < u8 > > {
2020-11-08 20:28:21 +01:00
let prog = self . get_ref ( ) ? ;
Ok ( match q {
CL_PROGRAM_CONTEXT = > {
// Note we use as_ptr here which doesn't increase the reference count.
let ptr = Arc ::as_ptr ( & prog . context ) ;
cl_prop ::< cl_context > ( cl_context ::from_ptr ( ptr ) )
}
CL_PROGRAM_DEVICES = > {
cl_prop ::< & Vec < cl_device_id > > (
& prog
. devs
. iter ( )
. map ( | d | {
// Note we use as_ptr here which doesn't increase the reference count.
cl_device_id ::from_ptr ( Arc ::as_ptr ( d ) )
} )
. collect ( ) ,
)
}
2022-03-10 19:32:35 +01:00
CL_PROGRAM_KERNEL_NAMES = > cl_prop ::< String > ( prog . kernels ( ) . join ( " ; " ) ) ,
2020-11-08 20:28:21 +01:00
CL_PROGRAM_NUM_DEVICES = > cl_prop ::< cl_uint > ( prog . devs . len ( ) as cl_uint ) ,
CL_PROGRAM_NUM_KERNELS = > cl_prop ::< usize > ( prog . kernels ( ) . len ( ) ) ,
CL_PROGRAM_REFERENCE_COUNT = > cl_prop ::< cl_uint > ( self . refcnt ( ) ? ) ,
CL_PROGRAM_SOURCE = > cl_prop ::< & CStr > ( prog . src . as_c_str ( ) ) ,
// CL_INVALID_VALUE if param_name is not one of the supported values
_ = > return Err ( CL_INVALID_VALUE ) ,
} )
}
}
impl CLInfoObj < cl_program_build_info , cl_device_id > for cl_program {
fn query ( & self , d : cl_device_id , q : cl_program_build_info ) -> CLResult < Vec < u8 > > {
let prog = self . get_ref ( ) ? ;
let dev = d . get_arc ( ) ? ;
Ok ( match q {
2022-03-16 22:37:42 +01:00
CL_PROGRAM_BINARY_TYPE = > cl_prop ::< cl_program_binary_type > ( prog . bin_type ( & dev ) ) ,
2020-11-08 20:28:21 +01:00
CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE = > cl_prop ::< usize > ( 0 ) ,
CL_PROGRAM_BUILD_LOG = > cl_prop ::< String > ( prog . log ( & dev ) ) ,
CL_PROGRAM_BUILD_OPTIONS = > cl_prop ::< String > ( prog . options ( & dev ) ) ,
CL_PROGRAM_BUILD_STATUS = > cl_prop ::< cl_build_status > ( prog . status ( & dev ) ) ,
// CL_INVALID_VALUE if param_name is not one of the supported values
_ = > return Err ( CL_INVALID_VALUE ) ,
} )
}
}
fn validate_devices (
device_list : * const cl_device_id ,
num_devices : cl_uint ,
default : & [ Arc < Device > ] ,
) -> CLResult < Vec < Arc < Device > > > {
let mut devs = cl_device_id ::get_arc_vec_from_arr ( device_list , num_devices ) ? ;
// If device_list is a NULL value, the compile is performed for all devices associated with
// program.
if devs . is_empty ( ) {
devs = default . to_vec ( ) ;
}
Ok ( devs )
}
fn call_cb (
pfn_notify : Option < ProgramCB > ,
program : cl_program ,
user_data : * mut ::std ::os ::raw ::c_void ,
) {
if let Some ( cb ) = pfn_notify {
unsafe { cb ( program , user_data ) } ;
}
}
pub fn create_program_with_source (
context : cl_context ,
count : cl_uint ,
strings : * mut * const c_char ,
lengths : * const usize ,
) -> CLResult < cl_program > {
let c = context . get_arc ( ) ? ;
// CL_INVALID_VALUE if count is zero or if strings ...
if count = = 0 | | strings . is_null ( ) {
return Err ( CL_INVALID_VALUE ) ;
}
// ... or any entry in strings is NULL.
let srcs = unsafe { slice ::from_raw_parts ( strings , count as usize ) } ;
if srcs . contains ( & ptr ::null ( ) ) {
return Err ( CL_INVALID_VALUE ) ;
}
let mut source = String ::new ( ) ;
// we don't want encoding or any other problems with the source to prevent compilations, so
// just use CString::from_vec_unchecked and to_string_lossy
for i in 0 .. count as usize {
unsafe {
if lengths . is_null ( ) | | * lengths . add ( i ) = = 0 {
source . push_str ( & CStr ::from_ptr ( * strings . add ( i ) ) . to_string_lossy ( ) ) ;
} else {
let l = * lengths . add ( i ) ;
let arr = slice ::from_raw_parts ( * strings . add ( i ) . cast ( ) , l ) ;
source . push_str ( & CString ::from_vec_unchecked ( arr . to_vec ( ) ) . to_string_lossy ( ) ) ;
}
}
}
Ok ( cl_program ::from_arc ( Program ::new (
& c ,
& c . devs ,
CString ::new ( source ) . map_err ( | _ | CL_INVALID_VALUE ) ? ,
) ) )
}
pub fn build_program (
program : cl_program ,
num_devices : cl_uint ,
device_list : * const cl_device_id ,
options : * const c_char ,
pfn_notify : Option < ProgramCB > ,
user_data : * mut ::std ::os ::raw ::c_void ,
) -> CLResult < ( ) > {
let mut res = true ;
let p = program . get_ref ( ) ? ;
let devs = validate_devices ( device_list , num_devices , & p . devs ) ? ;
check_cb ( & pfn_notify , user_data ) ? ;
// CL_BUILD_PROGRAM_FAILURE if there is a failure to build the program executable. This error
// will be returned if clBuildProgram does not return until the build has completed.
for dev in devs {
2022-03-09 18:02:03 +01:00
res & = p . build ( & dev , c_string_to_string ( options ) ) ;
2020-11-08 20:28:21 +01:00
}
call_cb ( pfn_notify , program , user_data ) ;
//• CL_INVALID_BINARY if program is created with clCreateProgramWithBinary and devices listed in device_list do not have a valid program binary loaded.
//• CL_INVALID_BUILD_OPTIONS if the build options specified by options are invalid.
//• CL_INVALID_OPERATION if the build of a program executable for any of the devices listed in device_list by a previous call to clBuildProgram for program has not completed.
//• CL_INVALID_OPERATION if there are kernel objects attached to program.
//• CL_INVALID_OPERATION if program was not created with clCreateProgramWithSource, clCreateProgramWithIL or clCreateProgramWithBinary.
if res {
Ok ( ( ) )
} else {
Err ( CL_BUILD_PROGRAM_FAILURE )
}
}
pub fn compile_program (
program : cl_program ,
num_devices : cl_uint ,
device_list : * const cl_device_id ,
options : * const c_char ,
num_input_headers : cl_uint ,
input_headers : * const cl_program ,
header_include_names : * mut * const c_char ,
pfn_notify : Option < ProgramCB > ,
user_data : * mut ::std ::os ::raw ::c_void ,
) -> CLResult < ( ) > {
let mut res = true ;
let p = program . get_ref ( ) ? ;
let devs = validate_devices ( device_list , num_devices , & p . devs ) ? ;
check_cb ( & pfn_notify , user_data ) ? ;
// CL_INVALID_VALUE if num_input_headers is zero and header_include_names or input_headers are
// not NULL or if num_input_headers is not zero and header_include_names or input_headers are
// NULL.
if num_input_headers = = 0 & & ( ! header_include_names . is_null ( ) | | ! input_headers . is_null ( ) )
| | num_input_headers ! = 0 & & ( header_include_names . is_null ( ) | | input_headers . is_null ( ) )
{
return Err ( CL_INVALID_VALUE ) ;
}
let mut headers = Vec ::new ( ) ;
for h in 0 .. num_input_headers as usize {
unsafe {
headers . push ( spirv ::CLCHeader {
name : CStr ::from_ptr ( * header_include_names . add ( h ) ) . to_owned ( ) ,
source : & ( * input_headers . add ( h ) ) . get_ref ( ) ? . src ,
} ) ;
}
}
// CL_COMPILE_PROGRAM_FAILURE if there is a failure to compile the program source. This error
// will be returned if clCompileProgram does not return until the compile has completed.
for dev in devs {
res & = p . compile ( & dev , c_string_to_string ( options ) , & headers ) ;
}
call_cb ( pfn_notify , program , user_data ) ;
// CL_INVALID_OPERATION if program has no source or IL available, i.e. it has not been created with clCreateProgramWithSource or clCreateProgramWithIL.
// • CL_INVALID_COMPILER_OPTIONS if the compiler options specified by options are invalid.
// • CL_INVALID_OPERATION if the compilation or build of a program executable for any of the devices listed in device_list by a previous call to clCompileProgram or clBuildProgram for program has not completed.
// • CL_INVALID_OPERATION if there are kernel objects attached to program.
if res {
Ok ( ( ) )
} else {
Err ( CL_COMPILE_PROGRAM_FAILURE )
}
}
pub fn link_program (
context : cl_context ,
num_devices : cl_uint ,
device_list : * const cl_device_id ,
2022-03-16 22:37:42 +01:00
options : * const ::std ::os ::raw ::c_char ,
2020-11-08 20:28:21 +01:00
num_input_programs : cl_uint ,
input_programs : * const cl_program ,
pfn_notify : Option < ProgramCB > ,
user_data : * mut ::std ::os ::raw ::c_void ,
) -> CLResult < ( cl_program , cl_int ) > {
let c = context . get_arc ( ) ? ;
let devs = validate_devices ( device_list , num_devices , & c . devs ) ? ;
let progs = cl_program ::get_arc_vec_from_arr ( input_programs , num_input_programs ) ? ;
check_cb ( & pfn_notify , user_data ) ? ;
// CL_INVALID_VALUE if num_input_programs is zero and input_programs is NULL
if progs . is_empty ( ) {
return Err ( CL_INVALID_VALUE ) ;
}
// CL_INVALID_DEVICE if any device in device_list is not in the list of devices associated with
// context.
if ! devs . iter ( ) . all ( | d | c . devs . contains ( d ) ) {
return Err ( CL_INVALID_DEVICE ) ;
}
// CL_INVALID_OPERATION if the compilation or build of a program executable for any of the
// devices listed in device_list by a previous call to clCompileProgram or clBuildProgram for
// program has not completed.
for d in & devs {
if progs
. iter ( )
. map ( | p | p . status ( d ) )
. any ( | s | s ! = CL_BUILD_SUCCESS as cl_build_status )
{
return Err ( CL_INVALID_OPERATION ) ;
}
}
// CL_LINK_PROGRAM_FAILURE if there is a failure to link the compiled binaries and/or libraries.
2022-03-16 22:37:42 +01:00
let res = Program ::link ( c , & devs , & progs , c_string_to_string ( options ) ) ;
2020-11-08 20:28:21 +01:00
let code = if devs
. iter ( )
. map ( | d | res . status ( d ) )
. all ( | s | s = = CL_BUILD_SUCCESS as cl_build_status )
{
CL_SUCCESS as cl_int
} else {
CL_LINK_PROGRAM_FAILURE
} ;
let res = cl_program ::from_arc ( res ) ;
call_cb ( pfn_notify , res , user_data ) ;
Ok ( ( res , code ) )
//• CL_INVALID_LINKER_OPTIONS if the linker options specified by options are invalid.
//• CL_INVALID_OPERATION if the rules for devices containing compiled binaries or libraries as described in input_programs argument above are not followed.
}