diff --git a/src/gallium/frontends/rusticl/api/device.rs b/src/gallium/frontends/rusticl/api/device.rs index 41d0a73b8ce..96d5d43a038 100644 --- a/src/gallium/frontends/rusticl/api/device.rs +++ b/src/gallium/frontends/rusticl/api/device.rs @@ -12,6 +12,18 @@ use std::ptr; use std::sync::Arc; use std::sync::Once; +// TODO spec constants need to be implemented +const SPIRV_SUPPORT_STRING: &str = ""; +// "SPIR-V_1.0 SPIR-V_1.1 SPIR-V_1.2 SPIR-V_1.3 SPIR-V_1.4 SPIR-V_1.5"; +const SPIRV_SUPPORT: [cl_name_version; 0] = [ +/* mk_cl_version_ext(1, 0, 0, b"SPIR-V"), + mk_cl_version_ext(1, 1, 0, b"SPIR-V"), + mk_cl_version_ext(1, 2, 0, b"SPIR-V"), + mk_cl_version_ext(1, 3, 0, b"SPIR-V"), + mk_cl_version_ext(1, 4, 0, b"SPIR-V"), + mk_cl_version_ext(1, 5, 0, b"SPIR-V"),*/ +]; + impl CLInfo for cl_device_id { fn query(&self, q: cl_device_info, _: &[u8]) -> CLResult> { let dev = self.get_ref()?; @@ -61,8 +73,8 @@ impl CLInfo for cl_device_id { CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE => cl_prop::(0), CL_DEVICE_HALF_FP_CONFIG => cl_prop::(0), CL_DEVICE_HOST_UNIFIED_MEMORY => cl_prop::(dev.unified_memory()), - CL_DEVICE_IL_VERSION => cl_prop::<&str>(""), - CL_DEVICE_ILS_WITH_VERSION => cl_prop::>(Vec::new()), + CL_DEVICE_IL_VERSION => cl_prop::<&str>(SPIRV_SUPPORT_STRING), + CL_DEVICE_ILS_WITH_VERSION => cl_prop::>(SPIRV_SUPPORT.to_vec()), CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT => { cl_prop::(dev.image_base_address_alignment()) } diff --git a/src/gallium/frontends/rusticl/api/icd.rs b/src/gallium/frontends/rusticl/api/icd.rs index 2af97412f69..8282fa99253 100644 --- a/src/gallium/frontends/rusticl/api/icd.rs +++ b/src/gallium/frontends/rusticl/api/icd.rs @@ -1258,8 +1258,9 @@ extern "C" fn cl_get_extension_function_address( return ptr::null_mut(); } match unsafe { CStr::from_ptr(function_name) }.to_str().unwrap() { - "clGetPlatformInfo" => cl_get_platform_info as *mut std::ffi::c_void, - "clIcdGetPlatformIDsKHR" => cl_icd_get_platform_ids_khr as *mut std::ffi::c_void, + "clCreateProgramWithILKHR" => cl_create_program_with_il as *mut ::std::ffi::c_void, + "clGetPlatformInfo" => cl_get_platform_info as *mut ::std::ffi::c_void, + "clIcdGetPlatformIDsKHR" => cl_icd_get_platform_ids_khr as *mut ::std::ffi::c_void, _ => ptr::null_mut(), } } diff --git a/src/gallium/frontends/rusticl/api/platform.rs b/src/gallium/frontends/rusticl/api/platform.rs index ff4977d3544..3dd7624098e 100644 --- a/src/gallium/frontends/rusticl/api/platform.rs +++ b/src/gallium/frontends/rusticl/api/platform.rs @@ -17,7 +17,9 @@ impl CLInfo for cl_platform_id { fn query(&self, q: cl_platform_info, _: &[u8]) -> CLResult> { let p = self.get_ref()?; Ok(match q { + // TODO spirv CL_PLATFORM_EXTENSIONS => cl_prop("cl_khr_icd"), + // CL_PLATFORM_EXTENSIONS => cl_prop("cl_khr_icd cl_khr_il_program"), CL_PLATFORM_EXTENSIONS_WITH_VERSION => { cl_prop::>(p.extensions.to_vec()) } @@ -37,7 +39,11 @@ impl CLInfo for cl_platform_id { static PLATFORM: _cl_platform_id = _cl_platform_id { dispatch: &DISPATCH, - extensions: [mk_cl_version_ext(1, 0, 0, "cl_khr_icd")], + extensions: [ + mk_cl_version_ext(1, 0, 0, "cl_khr_icd"), + // TODO spirv + // mk_cl_version_ext(1, 0, 0, "cl_khr_il_program"), + ], }; pub fn get_platform() -> cl_platform_id { diff --git a/src/gallium/frontends/rusticl/api/program.rs b/src/gallium/frontends/rusticl/api/program.rs index ed264a783ea..839fc752b15 100644 --- a/src/gallium/frontends/rusticl/api/program.rs +++ b/src/gallium/frontends/rusticl/api/program.rs @@ -38,7 +38,7 @@ impl CLInfo for cl_program { .collect(), ) } - CL_PROGRAM_IL => Vec::new(), + CL_PROGRAM_IL => prog.il.clone(), CL_PROGRAM_KERNEL_NAMES => cl_prop::(prog.kernels().join(";")), CL_PROGRAM_NUM_DEVICES => cl_prop::(prog.devs.len() as cl_uint), CL_PROGRAM_NUM_KERNELS => cl_prop::(prog.kernels().len()), @@ -195,17 +195,20 @@ pub fn create_program_with_binary( pub fn create_program_with_il( context: cl_context, - _il: *const ::std::os::raw::c_void, - _length: usize, + il: *const ::std::os::raw::c_void, + length: usize, ) -> CLResult { - let _c = context.get_ref()?; + let _c = context.get_arc()?; - println!("create_program_with_il not implemented"); + // CL_INVALID_VALUE if il is NULL or if length is zero. + if il.is_null() || length == 0 { + return Err(CL_INVALID_VALUE); + } + + // let spirv = unsafe { slice::from_raw_parts(il.cast(), length) }; + // TODO SPIR-V + // Ok(cl_program::from_arc(Program::from_spirv(c, spirv))) Err(CL_INVALID_OPERATION) - //• CL_INVALID_CONTEXT if context is not a valid context. - //• CL_INVALID_OPERATION if no devices in context support intermediate language programs. - //• CL_INVALID_VALUE if il is NULL or if length is zero. - //• CL_INVALID_VALUE if the length-byte memory pointed to by il does not contain well-formed intermediate language input that can be consumed by the OpenCL runtime. } pub fn build_program( @@ -361,13 +364,30 @@ pub fn link_program( } pub fn set_program_specialization_constant( - _program: cl_program, + program: cl_program, _spec_id: cl_uint, _spec_size: usize, - _spec_value: *const ::std::os::raw::c_void, + spec_value: *const ::std::os::raw::c_void, ) -> CLResult<()> { - println!("set_program_specialization_constantnot implemented"); + let _program = program.get_ref()?; + + // CL_INVALID_PROGRAM if program is not a valid program object created from an intermediate + // language (e.g. SPIR-V) + // TODO: or if the intermediate language does not support specialization constants. + // if program.il.is_empty() { + // Err(CL_INVALID_PROGRAM)? + // } + + // TODO: CL_INVALID_VALUE if spec_size does not match the size of the specialization constant in the module, + + // or if spec_value is NULL. + if spec_value.is_null() { + return Err(CL_INVALID_VALUE); + } + Err(CL_INVALID_OPERATION) + + //• CL_INVALID_SPEC_ID if spec_id is not a valid specialization constant identifier. } pub fn set_program_release_callback( diff --git a/src/gallium/frontends/rusticl/api/util.rs b/src/gallium/frontends/rusticl/api/util.rs index 99dd0c04353..9a5b21e8f2c 100644 --- a/src/gallium/frontends/rusticl/api/util.rs +++ b/src/gallium/frontends/rusticl/api/util.rs @@ -116,6 +116,7 @@ macro_rules! cl_prop_for_struct { } cl_prop_for_type!(cl_char); +cl_prop_for_type!(cl_uchar); cl_prop_for_type!(cl_ushort); cl_prop_for_type!(cl_int); cl_prop_for_type!(cl_uint); @@ -176,6 +177,19 @@ where } } +impl CLProp for [T] +where + T: CLProp, +{ + fn cl_vec(&self) -> Vec { + let mut res: Vec = Vec::new(); + for i in self { + res.append(&mut i.cl_vec()) + } + res + } +} + impl CLProp for [T; I] where T: CLProp, @@ -225,7 +239,10 @@ where } } -pub fn cl_prop(v: T) -> Vec { +pub fn cl_prop(v: T) -> Vec +where + T: Sized, +{ v.cl_vec() } diff --git a/src/gallium/frontends/rusticl/core/device.rs b/src/gallium/frontends/rusticl/core/device.rs index f64a32ce814..e629c06c67c 100644 --- a/src/gallium/frontends/rusticl/core/device.rs +++ b/src/gallium/frontends/rusticl/core/device.rs @@ -400,6 +400,8 @@ impl Device { add_ext(1, 0, 0, "cl_khr_byte_addressable_store", ""); add_ext(1, 0, 0, "cl_khr_global_int32_base_atomics", ""); add_ext(1, 0, 0, "cl_khr_global_int32_extended_atomics", ""); + // TODO spirv + // add_ext(1, 0, 0, "cl_khr_il_program", ""); add_ext(1, 0, 0, "cl_khr_local_int32_base_atomics", ""); add_ext(1, 0, 0, "cl_khr_local_int32_extended_atomics", ""); diff --git a/src/gallium/frontends/rusticl/core/program.rs b/src/gallium/frontends/rusticl/core/program.rs index b97a183b3b6..d687dc2a8f7 100644 --- a/src/gallium/frontends/rusticl/core/program.rs +++ b/src/gallium/frontends/rusticl/core/program.rs @@ -49,6 +49,8 @@ pub struct Program { pub context: Arc, pub devs: Vec>, pub src: CString, + pub il: Vec, + spec_constants: Mutex>, build: Mutex, } @@ -112,6 +114,8 @@ impl Program { context: context.clone(), devs: devs.to_vec(), src: src, + il: Vec::new(), + spec_constants: Mutex::new(Vec::new()), build: Mutex::new(ProgramBuild { builds: builds, kernels: Vec::new(), @@ -150,10 +154,10 @@ impl Program { // 4. the spirv assert!(b.as_ptr().add(BIN_HEADER_SIZE_V1) == ptr); assert!(b.len() == BIN_HEADER_SIZE_V1 + spirv_size as usize); - spirv = Some(spirv::SPIRVBin::from_bin( - slice::from_raw_parts(ptr, spirv_size as usize), - bin_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE, - )); + spirv = Some(spirv::SPIRVBin::from_bin(slice::from_raw_parts( + ptr, + spirv_size as usize, + ))); } _ => panic!("unknown version"), } @@ -182,6 +186,8 @@ impl Program { context: context, devs: devs, src: CString::new("").unwrap(), + il: Vec::new(), + spec_constants: Mutex::new(Vec::new()), build: Mutex::new(ProgramBuild { builds: builds, kernels: kernels.into_iter().collect(), @@ -189,6 +195,38 @@ impl Program { }) } + pub fn from_spirv(context: Arc, spirv: &[u8]) -> Arc { + let mut builds = HashMap::new(); + + for d in &context.devs { + let spirv = Some(spirv::SPIRVBin::from_bin(spirv)); + + builds.insert( + d.clone(), + ProgramDevBuild { + spirv: spirv, + status: CL_BUILD_SUCCESS as cl_build_status, + log: String::from(""), + options: String::from(""), + bin_type: CL_PROGRAM_BINARY_TYPE_INTERMEDIATE, + }, + ); + } + + Arc::new(Self { + base: CLObjectBase::new(), + devs: context.devs.clone(), + context: context, + src: CString::new("").unwrap(), + il: spirv.to_vec(), + spec_constants: Mutex::new(Vec::new()), + build: Mutex::new(ProgramBuild { + builds: builds, + kernels: Vec::new(), + }), + }) + } + fn build_info(&self) -> MutexGuard { self.build.lock().unwrap() } @@ -293,31 +331,36 @@ impl Program { pub fn build(&self, dev: &Arc, options: String) -> bool { // program binary - if self.src.as_bytes().is_empty() { + let is_il = !self.il.is_empty(); + if self.src.as_bytes().is_empty() && !is_il { return true; } let mut info = self.build_info(); let d = Self::dev_build_info(&mut info, dev); let lib = options.contains("-create-library"); - let args = prepare_options(&options, dev); - let (spirv, log) = spirv::SPIRVBin::from_clc( - &self.src, - &args, - &Vec::new(), - get_disk_cache(), - dev.cl_features(), - ); - d.log = log; - d.options = options; - if spirv.is_none() { - d.status = CL_BUILD_ERROR; - return false; + if !is_il { + let (spirv, log) = spirv::SPIRVBin::from_clc( + &self.src, + &args, + &Vec::new(), + get_disk_cache(), + dev.cl_features(), + ); + + d.log = log; + if spirv.is_none() { + d.status = CL_BUILD_ERROR; + return false; + } + d.spirv = spirv; } - let spirvs = vec![spirv.as_ref().unwrap()]; + d.options = options; + + let spirvs = [d.spirv.as_ref().unwrap()]; let (spirv, log) = spirv::SPIRVBin::link(&spirvs, lib); d.log.push_str(&log); @@ -345,12 +388,19 @@ impl Program { headers: &[spirv::CLCHeader], ) -> bool { // program binary - if self.src.as_bytes().is_empty() { + let is_il = !self.il.is_empty(); + if self.src.as_bytes().is_empty() && !is_il { return true; } let mut info = self.build_info(); let d = Self::dev_build_info(&mut info, dev); + + if is_il { + d.bin_type = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; + return true; + } + let args = prepare_options(&options, dev); let (spirv, log) = spirv::SPIRVBin::from_clc( @@ -429,6 +479,8 @@ impl Program { context: context, devs: devs, src: CString::new("").unwrap(), + il: Vec::new(), + spec_constants: Mutex::new(Vec::new()), build: Mutex::new(ProgramBuild { builds: builds, kernels: kernels.into_iter().collect(), @@ -492,6 +544,7 @@ impl Program { d.screen .nir_shader_compiler_options(pipe_shader_type::PIPE_SHADER_COMPUTE), &d.lib_clc, + &mut [], ) .unwrap() } diff --git a/src/gallium/frontends/rusticl/mesa/compiler/clc/spirv.rs b/src/gallium/frontends/rusticl/mesa/compiler/clc/spirv.rs index a9bfca38c86..ea2a6eb08f1 100644 --- a/src/gallium/frontends/rusticl/mesa/compiler/clc/spirv.rs +++ b/src/gallium/frontends/rusticl/mesa/compiler/clc/spirv.rs @@ -14,6 +14,10 @@ use std::slice; const INPUT_STR: *const c_char = b"input.cl\0" as *const u8 as *const c_char; +pub enum SpecConstant { + None, +} + pub struct SPIRVBin { spirv: clc_binary, info: Option, @@ -63,7 +67,7 @@ impl SPIRVBin { let mut key = cache.gen_key(&key); if let Some(data) = cache.get(&mut key) { - return (Some(Self::from_bin(&data, false)), String::from("")); + return (Some(Self::from_bin(&data)), String::from("")); } hash_key = Some(key); @@ -285,15 +289,17 @@ impl SPIRVBin { entry_point: &str, nir_options: *const nir_shader_compiler_options, libclc: &NirShader, + spec_constants: &mut [nir_spirv_specialization], ) -> Option { let c_entry = CString::new(entry_point.as_bytes()).unwrap(); let spirv_options = Self::get_spirv_options(false, libclc.get_nir()); + let nir = unsafe { spirv_to_nir( self.spirv.data.cast(), self.spirv.size / 4, - ptr::null_mut(), // spec - 0, // spec count + spec_constants.as_mut_ptr(), + spec_constants.len() as u32, gl_shader_stage::MESA_SHADER_KERNEL, c_entry.as_ptr(), &spirv_options, @@ -317,7 +323,7 @@ impl SPIRVBin { unsafe { slice::from_raw_parts(self.spirv.data.cast(), self.spirv.size) } } - pub fn from_bin(bin: &[u8], executable: bool) -> Self { + pub fn from_bin(bin: &[u8]) -> Self { unsafe { let ptr = malloc(bin.len()); ptr::copy_nonoverlapping(bin.as_ptr(), ptr.cast(), bin.len()); @@ -325,9 +331,10 @@ impl SPIRVBin { data: ptr, size: bin.len(), }; - let info = if executable { - let mut pspirv = clc_parsed_spirv::default(); - clc_parse_spirv(&spirv, ptr::null(), &mut pspirv); + + let mut pspirv = clc_parsed_spirv::default(); + + let info = if clc_parse_spirv(&spirv, ptr::null(), &mut pspirv) { Some(pspirv) } else { None