mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-11 23:10:28 +01:00
rusticl/program: some boilerplate code for SPIR-V support
Signed-off-by: Karol Herbst <kherbst@redhat.com> Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15439>
This commit is contained in:
parent
1b00d4f22e
commit
734352ddfb
8 changed files with 163 additions and 45 deletions
|
|
@ -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<cl_device_info> for cl_device_id {
|
||||
fn query(&self, q: cl_device_info, _: &[u8]) -> CLResult<Vec<u8>> {
|
||||
let dev = self.get_ref()?;
|
||||
|
|
@ -61,8 +73,8 @@ impl CLInfo<cl_device_info> for cl_device_id {
|
|||
CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE => cl_prop::<usize>(0),
|
||||
CL_DEVICE_HALF_FP_CONFIG => cl_prop::<cl_device_fp_config>(0),
|
||||
CL_DEVICE_HOST_UNIFIED_MEMORY => cl_prop::<bool>(dev.unified_memory()),
|
||||
CL_DEVICE_IL_VERSION => cl_prop::<&str>(""),
|
||||
CL_DEVICE_ILS_WITH_VERSION => cl_prop::<Vec<cl_name_version>>(Vec::new()),
|
||||
CL_DEVICE_IL_VERSION => cl_prop::<&str>(SPIRV_SUPPORT_STRING),
|
||||
CL_DEVICE_ILS_WITH_VERSION => cl_prop::<Vec<cl_name_version>>(SPIRV_SUPPORT.to_vec()),
|
||||
CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT => {
|
||||
cl_prop::<cl_uint>(dev.image_base_address_alignment())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ impl CLInfo<cl_platform_info> for cl_platform_id {
|
|||
fn query(&self, q: cl_platform_info, _: &[u8]) -> CLResult<Vec<u8>> {
|
||||
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::<Vec<cl_name_version>>(p.extensions.to_vec())
|
||||
}
|
||||
|
|
@ -37,7 +39,11 @@ impl CLInfo<cl_platform_info> 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 {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl CLInfo<cl_program_info> for cl_program {
|
|||
.collect(),
|
||||
)
|
||||
}
|
||||
CL_PROGRAM_IL => Vec::new(),
|
||||
CL_PROGRAM_IL => prog.il.clone(),
|
||||
CL_PROGRAM_KERNEL_NAMES => cl_prop::<String>(prog.kernels().join(";")),
|
||||
CL_PROGRAM_NUM_DEVICES => cl_prop::<cl_uint>(prog.devs.len() as cl_uint),
|
||||
CL_PROGRAM_NUM_KERNELS => cl_prop::<usize>(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<cl_program> {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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<T> CLProp for [T]
|
||||
where
|
||||
T: CLProp,
|
||||
{
|
||||
fn cl_vec(&self) -> Vec<u8> {
|
||||
let mut res: Vec<u8> = Vec::new();
|
||||
for i in self {
|
||||
res.append(&mut i.cl_vec())
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const I: usize> CLProp for [T; I]
|
||||
where
|
||||
T: CLProp,
|
||||
|
|
@ -225,7 +239,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cl_prop<T: CLProp>(v: T) -> Vec<u8> {
|
||||
pub fn cl_prop<T: CLProp>(v: T) -> Vec<u8>
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
v.cl_vec()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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", "");
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ pub struct Program {
|
|||
pub context: Arc<Context>,
|
||||
pub devs: Vec<Arc<Device>>,
|
||||
pub src: CString,
|
||||
pub il: Vec<u8>,
|
||||
spec_constants: Mutex<Vec<spirv::SpecConstant>>,
|
||||
build: Mutex<ProgramBuild>,
|
||||
}
|
||||
|
||||
|
|
@ -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<Context>, spirv: &[u8]) -> Arc<Program> {
|
||||
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<ProgramBuild> {
|
||||
self.build.lock().unwrap()
|
||||
}
|
||||
|
|
@ -293,31 +331,36 @@ impl Program {
|
|||
|
||||
pub fn build(&self, dev: &Arc<Device>, 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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<clc_parsed_spirv>,
|
||||
|
|
@ -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<NirShader> {
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue