diff --git a/src/gallium/frontends/rusticl/api/program.rs b/src/gallium/frontends/rusticl/api/program.rs index 62a630bcc97..c4fbc71f717 100644 --- a/src/gallium/frontends/rusticl/api/program.rs +++ b/src/gallium/frontends/rusticl/api/program.rs @@ -309,7 +309,7 @@ fn build_program( pfn_notify: Option, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<()> { - let p = Program::ref_from_raw(program)?; + let p = Program::arc_from_raw(program)?; let devs = validate_devices(device_list, num_devices, &p.devs)?; // SAFETY: The requirements on `ProgramCB::try_new` match the requirements @@ -321,25 +321,15 @@ fn build_program( return Err(CL_INVALID_OPERATION); } - // 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. let options = c_string_to_string(options); - let res = p.build(&devs, &options); - - if let Some(cb) = cb_opt { - cb.call(p); - } + let res = p.build(devs, options, cb_opt); //• 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 program was not created with clCreateProgramWithSource, clCreateProgramWithIL or clCreateProgramWithBinary. - if res { - Ok(()) - } else { - Err(CL_BUILD_PROGRAM_FAILURE) - } + res } #[cl_entrypoint(clCompileProgram)] @@ -354,7 +344,7 @@ fn compile_program( pfn_notify: Option, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<()> { - let p = Program::ref_from_raw(program)?; + let p = Program::arc_from_raw(program)?; let devs = validate_devices(device_list, num_devices, &p.devs)?; // SAFETY: The requirements on `ProgramCB::try_new` match the requirements @@ -408,23 +398,13 @@ fn compile_program( return Err(CL_INVALID_OPERATION); } - // 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. let options = c_string_to_string(options); - let res = p.compile(&devs, &options, &headers); - - if let Some(cb) = cb_opt { - cb.call(p); - } + let res = p.compile(devs, options, headers, cb_opt); // • 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. - if res { - Ok(()) - } else { - Err(CL_COMPILE_PROGRAM_FAILURE) - } + res } pub fn link_program( @@ -459,31 +439,11 @@ pub fn link_program( // 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); - } + if progs.iter().any(|p| !p.all_devices_succeeded(&devs)) { + return Err(CL_INVALID_OPERATION); } - // CL_LINK_PROGRAM_FAILURE if there is a failure to link the compiled binaries and/or libraries. - let res = Program::link(c, &devs, &progs, c_string_to_string(options)); - 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 - }; - - if let Some(cb) = cb_opt { - cb.call(&res); - } + let (res, code) = Program::link(c, devs, progs, c_string_to_string(options), cb_opt)?; Ok((res.into_cl(), code)) diff --git a/src/gallium/frontends/rusticl/core/program.rs b/src/gallium/frontends/rusticl/core/program.rs index 3e979fe496a..f95cbe74e18 100644 --- a/src/gallium/frontends/rusticl/core/program.rs +++ b/src/gallium/frontends/rusticl/core/program.rs @@ -1,4 +1,5 @@ use crate::api::icd::*; +use crate::api::types::ProgramCB; use crate::core::context::*; use crate::core::device::*; use crate::core::kernel::*; @@ -567,14 +568,17 @@ impl Program { .any(|k| Arc::strong_count(k) > 1) } - pub fn build(&self, devs: &[&'static Device], options: &str) -> bool { + pub fn build( + self: Arc, + devs: Vec<&'static Device>, + options: String, + callback: Option, + ) -> CLResult<()> { let lib = options.contains("-create-library"); let mut info = self.build_info(); - let mut res = true; - for dev in devs { - if !self.do_compile(dev, options, &[], &mut info) { - res = false; + for &dev in &devs { + if !self.do_compile(dev, &options, &[], &mut info) { continue; } @@ -594,17 +598,29 @@ impl Program { // Don't request validation of the SPIR-V, as we've just done that // as part of compilation. Self::do_link(d, &spirvs, lib, None); - - if d.status == CL_BUILD_ERROR { - res = false - } } - info.rebuild_kernels(devs, self.is_src()); + info.rebuild_kernels(&devs, self.is_src()); - debug_logging(self, devs); + // The callback must be called after we've dropped any mutex locks we're + // holding. + drop(info); - res + if let Some(callback) = callback { + callback.call(&self); + } + + debug_logging(&self, &devs); + + if !self.all_devices_succeeded(&devs) { + // clBuildProgram returns 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. + return Err(CL_BUILD_PROGRAM_FAILURE); + } + + Ok(()) } fn do_compile( @@ -694,28 +710,46 @@ impl Program { } } - pub fn compile(&self, devs: &[&Device], options: &str, headers: &[HeaderProgram]) -> bool { - let mut res = true; - for dev in devs { - res &= self.do_compile(dev, options, headers, &mut self.build_info()); + pub fn compile( + self: Arc, + devs: Vec<&Device>, + options: String, + headers: Vec, + callback: Option, + ) -> CLResult<()> { + for &dev in &devs { + self.do_compile(dev, &options, &headers, &mut self.build_info()); } - debug_logging(self, devs); + if let Some(callback) = callback { + callback.call(&self); + } - res + debug_logging(&self, &devs); + + if !self.all_devices_succeeded(&devs) { + // clCompileProgram returns 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. + return Err(CL_COMPILE_PROGRAM_FAILURE); + } + + Ok(()) } pub fn link( context: Arc, - devs: &[&'static Device], - progs: &[Arc], + devs: Vec<&'static Device>, + progs: Vec>, options: String, - ) -> Arc { + callback: Option, + ) -> CLResult<(Arc, cl_int)> { let mut builds = HashMap::new(); let mut locks: Vec<_> = progs.iter().map(|p| p.build_info()).collect(); let lib = options.contains("-create-library"); - for &d in devs { + for &d in &devs { let bins: Vec<_> = locks .iter_mut() .map(|l| l.dev_build(d).spirv.as_ref().unwrap()) @@ -741,19 +775,31 @@ impl Program { }; // Pre build nir kernels - build.rebuild_kernels(devs, false); + build.rebuild_kernels(&devs, false); let res = Arc::new(Self { base: CLObjectBase::new(RusticlTypes::Program), context: context, - devs: devs.to_owned(), + devs: devs.clone(), src: ProgramSourceType::Linked, build: Mutex::new(build), }); + if let Some(callback) = callback { + callback.call(&res); + } + debug_logging(&res, &devs); - res + let status = if res.all_devices_succeeded(&devs) { + CL_SUCCESS as cl_int + } else { + // clLinkProgram returns CL_LINK_PROGRAM_FAILURE if there is a + // failure to link the compiled binaries and/or libraries. + CL_LINK_PROGRAM_FAILURE + }; + + Ok((res, status)) } /// Performs linking of the provided SPIR-V binaries. @@ -795,6 +841,14 @@ impl Program { }; } + /// Returns `true` if build succeeded for each of the provided devices, + /// false otherwise. + pub fn all_devices_succeeded(&self, devices: &[&Device]) -> bool { + devices + .iter() + .all(|&device| self.status(device) == CL_BUILD_SUCCESS as cl_build_status) + } + pub fn is_bin(&self) -> bool { matches!(self.src, ProgramSourceType::Binary) }