54
57
Il(spirv::SPIRVBin),
58
60
pub struct Program {
59
61
pub base: CLObjectBase<CL_INVALID_PROGRAM>,
60
62
pub context: Arc<Context>,
61
pub devs: Vec<Arc<Device>>,
63
pub devs: Vec<&'static Device>,
62
64
pub src: ProgramSourceType,
63
pub kernel_count: AtomicU32,
64
spec_constants: Mutex<HashMap<u32, nir_const_value>>,
65
65
build: Mutex<ProgramBuild>,
68
68
impl_cl_type_trait!(cl_program, Program, CL_INVALID_PROGRAM);
71
builds: HashMap<Arc<Device>, ProgramDevBuild>,
71
pub struct NirKernelBuild {
72
pub nirs: HashMap<&'static Device, Arc<NirShader>>,
73
pub args: Vec<KernelArg>,
74
pub internal_args: Vec<InternalKernelArg>,
75
pub attributes_string: String,
78
pub(super) struct ProgramBuild {
79
builds: HashMap<&'static Device, ProgramDevBuild>,
80
spec_constants: HashMap<u32, nir_const_value>,
72
81
kernels: Vec<String>,
82
kernel_builds: HashMap<String, Arc<NirKernelBuild>>,
86
fn attribute_str(&self, kernel: &str, d: &Device) -> String {
87
let info = self.dev_build(d);
89
let attributes_strings = [
90
info.spirv.as_ref().unwrap().vec_type_hint(kernel),
91
info.spirv.as_ref().unwrap().local_size(kernel),
92
info.spirv.as_ref().unwrap().local_size_hint(kernel),
95
let attributes_strings: Vec<_> = attributes_strings
100
attributes_strings.join(",")
103
fn args(&self, dev: &Device, kernel: &str) -> Vec<spirv::SPIRVKernelArg> {
104
self.dev_build(dev).spirv.as_ref().unwrap().args(kernel)
107
fn build_nirs(&mut self, is_src: bool) {
108
for kernel_name in &self.kernels {
109
let kernel_args: HashSet<_> = self
112
.map(|d| self.args(d, kernel_name))
115
let args = kernel_args.into_iter().next().unwrap();
116
let mut nirs = HashMap::new();
117
let mut args_set = HashSet::new();
118
let mut internal_args_set = HashSet::new();
119
let mut attributes_string_set = HashSet::new();
121
// TODO: we could run this in parallel?
122
for d in self.devs_with_build() {
123
let (nir, args, internal_args) = convert_spirv_to_nir(self, kernel_name, &args, d);
124
let attributes_string = self.attribute_str(kernel_name, d);
125
nirs.insert(d, Arc::new(nir));
126
args_set.insert(args);
127
internal_args_set.insert(internal_args);
128
attributes_string_set.insert(attributes_string);
131
// we want the same (internal) args for every compiled kernel, for now
132
assert!(args_set.len() == 1);
133
assert!(internal_args_set.len() == 1);
134
assert!(attributes_string_set.len() == 1);
135
let args = args_set.into_iter().next().unwrap();
136
let internal_args = internal_args_set.into_iter().next().unwrap();
138
// spec: For kernels not created from OpenCL C source and the clCreateProgramWithSource
139
// API call the string returned from this query [CL_KERNEL_ATTRIBUTES] will be empty.
140
let attributes_string = if is_src {
141
attributes_string_set.into_iter().next().unwrap()
146
self.kernel_builds.insert(
148
Arc::new(NirKernelBuild {
151
internal_args: internal_args,
152
attributes_string: attributes_string,
158
fn dev_build(&self, dev: &Device) -> &ProgramDevBuild {
159
self.builds.get(dev).unwrap()
162
fn dev_build_mut(&mut self, dev: &Device) -> &mut ProgramDevBuild {
163
self.builds.get_mut(dev).unwrap()
166
fn devs_with_build(&self) -> Vec<&'static Device> {
169
.filter(|(_, build)| build.status == CL_BUILD_SUCCESS as cl_build_status)
174
pub fn hash_key(&self, dev: &Device, name: &str) -> Option<cache_key> {
175
if let Some(cache) = dev.screen().shader_cache() {
176
let info = self.dev_build(dev);
177
assert_eq!(info.status, CL_BUILD_SUCCESS as cl_build_status);
179
let spirv = info.spirv.as_ref().unwrap();
180
let mut bin = spirv.to_bin().to_vec();
181
bin.extend_from_slice(name.as_bytes());
183
for (k, v) in &self.spec_constants {
184
bin.extend_from_slice(&k.to_ne_bytes());
186
// SAFETY: we fully initialize this union
187
bin.extend_from_slice(&v.u64_.to_ne_bytes());
191
Some(cache.gen_key(&bin))
197
pub fn to_nir(&self, kernel: &str, d: &Device) -> NirShader {
198
let mut spec_constants: Vec<_> = self
201
.map(|(&id, &value)| nir_spirv_specialization {
204
defined_on_module: true,
208
let info = self.dev_build(d);
209
assert_eq!(info.status, CL_BUILD_SUCCESS as cl_build_status);
211
let mut log = Platform::dbg().program.then(Vec::new);
212
let nir = info.spirv.as_ref().unwrap().to_nir(
215
.nir_shader_compiler_options(pipe_shader_type::PIPE_SHADER_COMPUTE),
222
if let Some(log) = log {
224
eprintln!("{}", line);
75
232
struct ProgramDevBuild {
148
pub fn new(context: &Arc<Context>, devs: &[Arc<Device>], src: CString) -> Arc<Program> {
307
pub fn new(context: &Arc<Context>, devs: &[&'static Device], src: CString) -> Arc<Program> {
150
309
base: CLObjectBase::new(),
151
310
context: context.clone(),
152
311
devs: devs.to_vec(),
153
312
src: ProgramSourceType::Src(src),
154
kernel_count: AtomicU32::new(0),
155
spec_constants: Mutex::new(HashMap::new()),
156
313
build: Mutex::new(ProgramBuild {
157
314
builds: Self::create_default_builds(devs),
315
spec_constants: HashMap::new(),
158
316
kernels: Vec::new(),
317
kernel_builds: HashMap::new(),
163
322
pub fn from_bins(
164
323
context: Arc<Context>,
165
devs: Vec<Arc<Device>>,
324
devs: Vec<&'static Device>,
167
326
) -> Arc<Program> {
168
327
let mut builds = HashMap::new();
169
328
let mut kernels = HashSet::new();
171
for (d, b) in devs.iter().zip(bins) {
330
for (&d, b) in devs.iter().zip(bins) {
172
331
let mut ptr = b.as_ptr();
252
414
self.build.lock().unwrap()
255
fn dev_build_info<'a>(
256
l: &'a mut MutexGuard<ProgramBuild>,
258
) -> &'a mut ProgramDevBuild {
259
l.builds.get_mut(dev).unwrap()
262
pub fn status(&self, dev: &Arc<Device>) -> cl_build_status {
263
Self::dev_build_info(&mut self.build_info(), dev).status
266
pub fn log(&self, dev: &Arc<Device>) -> String {
267
Self::dev_build_info(&mut self.build_info(), dev)
272
pub fn bin_type(&self, dev: &Arc<Device>) -> cl_program_binary_type {
273
Self::dev_build_info(&mut self.build_info(), dev).bin_type
276
pub fn options(&self, dev: &Arc<Device>) -> String {
277
Self::dev_build_info(&mut self.build_info(), dev)
417
pub fn get_nir_kernel_build(&self, name: &str) -> Arc<NirKernelBuild> {
418
let info = self.build_info();
419
info.kernel_builds.get(name).unwrap().clone()
422
pub fn status(&self, dev: &Device) -> cl_build_status {
423
self.build_info().dev_build(dev).status
426
pub fn log(&self, dev: &Device) -> String {
427
self.build_info().dev_build(dev).log.clone()
430
pub fn bin_type(&self, dev: &Device) -> cl_program_binary_type {
431
self.build_info().dev_build(dev).bin_type
434
pub fn options(&self, dev: &Device) -> String {
435
self.build_info().dev_build(dev).options.clone()
282
438
// we need to precalculate the size
283
439
pub fn bin_sizes(&self) -> Vec<usize> {
284
let mut lock = self.build_info();
440
let lock = self.build_info();
285
441
let mut res = Vec::new();
286
442
for d in &self.devs {
287
let info = Self::dev_build_info(&mut lock, d);
443
let info = lock.dev_build(d);
353
512
pub fn active_kernels(&self) -> bool {
354
self.kernel_count.load(Ordering::Relaxed) != 0
516
.any(|b| Arc::strong_count(b) > 1)
357
pub fn build(&self, dev: &Arc<Device>, options: String) -> bool {
519
pub fn build(&self, dev: &Device, options: String) -> bool {
358
520
let lib = options.contains("-create-library");
359
521
let mut info = self.build_info();
360
522
if !self.do_compile(dev, options, &Vec::new(), &mut info) {
364
let d = Self::dev_build_info(&mut info, dev);
526
let d = info.dev_build_mut(dev);
528
// skip compilation if we already have the right thing.
530
if d.bin_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE && !lib
531
|| d.bin_type == CL_PROGRAM_BINARY_TYPE_LIBRARY && lib
365
537
let spirvs = [d.spirv.as_ref().unwrap()];
366
538
let (spirv, log) = spirv::SPIRVBin::link(&spirvs, lib);
368
540
d.log.push_str(&log);
370
if d.spirv.is_some() {
542
if let Some(spirv) = &d.spirv {
371
543
d.bin_type = if lib {
372
544
CL_PROGRAM_BINARY_TYPE_LIBRARY
374
546
CL_PROGRAM_BINARY_TYPE_EXECUTABLE
376
548
d.status = CL_BUILD_SUCCESS as cl_build_status;
377
let mut kernels = d.spirv.as_ref().unwrap().kernels();
549
let mut kernels = spirv.kernels();
378
550
info.kernels.append(&mut kernels);
551
info.build_nirs(self.is_src());
381
554
d.status = CL_BUILD_ERROR;
391
564
headers: &[spirv::CLCHeader],
392
565
info: &mut MutexGuard<ProgramBuild>,
394
let d = Self::dev_build_info(info, dev);
567
let d = info.dev_build_mut(dev);
396
569
let (spirv, log) = match &self.src {
397
ProgramSourceType::Il(spirv) => spirv.clone_on_validate(),
570
ProgramSourceType::Il(spirv) => {
571
let options = clc_validator_options {
572
// has to match CL_DEVICE_MAX_PARAMETER_SIZE
573
limit_max_function_arg: dev.param_max_size() as u32,
575
if Platform::dbg().allow_invalid_spirv {
576
(Some(spirv.clone()), String::new())
578
spirv.clone_on_validate(&options)
398
581
ProgramSourceType::Src(src) => {
399
582
let args = prepare_options(&options, dev);
584
if Platform::dbg().clc {
585
let src = src.to_string_lossy();
586
eprintln!("dumping compilation inputs:");
587
eprintln!("compilation arguments: {args:?}");
588
if !headers.is_empty() {
589
eprintln!("headers: {headers:#?}");
591
eprintln!("source code:\n{src}");
400
594
spirv::SPIRVBin::from_clc(
404
598
get_disk_cache(),
405
599
dev.cl_features(),
600
&dev.spirv_extensions,
406
601
dev.address_bits(),
433
headers: &[spirv::CLCHeader],
435
let mut info = self.build_info();
436
self.do_compile(dev, options, headers, &mut info)
624
pub fn compile(&self, dev: &Device, options: String, headers: &[spirv::CLCHeader]) -> bool {
625
self.do_compile(dev, options, headers, &mut self.build_info())
440
629
context: Arc<Context>,
441
devs: &[Arc<Device>],
630
devs: &[&'static Device],
442
631
progs: &[Arc<Program>],
444
633
) -> Arc<Program> {
445
let devs: Vec<Arc<Device>> = devs.iter().map(|d| (*d).clone()).collect();
446
634
let mut builds = HashMap::new();
447
635
let mut kernels = HashSet::new();
448
636
let mut locks: Vec<_> = progs.iter().map(|p| p.build_info()).collect();
449
637
let lib = options.contains("-create-library");
452
640
let bins: Vec<_> = locks
454
.map(|l| Self::dev_build_info(l, d).spirv.as_ref().unwrap())
642
.map(|l| l.dev_build(d).spirv.as_ref().unwrap())
457
645
let (spirv, log) = spirv::SPIRVBin::link(&bins, lib);
676
let mut build = ProgramBuild {
678
spec_constants: HashMap::new(),
679
kernels: kernels.into_iter().collect(),
680
kernel_builds: HashMap::new(),
683
// Pre build nir kernels
684
build.build_nirs(false);
489
687
base: CLObjectBase::new(),
490
688
context: context,
689
devs: devs.to_owned(),
492
690
src: ProgramSourceType::Linked,
493
kernel_count: AtomicU32::new(0),
494
spec_constants: Mutex::new(HashMap::new()),
495
build: Mutex::new(ProgramBuild {
497
kernels: kernels.into_iter().collect(),
691
build: Mutex::new(build),
502
pub(super) fn hash_key(&self, dev: &Arc<Device>, name: &str) -> Option<cache_key> {
503
if let Some(cache) = dev.screen().shader_cache() {
504
let mut lock = self.build_info();
505
let info = Self::dev_build_info(&mut lock, dev);
506
assert_eq!(info.status, CL_BUILD_SUCCESS as cl_build_status);
508
let spirv = info.spirv.as_ref().unwrap();
509
let mut bin = spirv.to_bin().to_vec();
510
bin.extend_from_slice(name.as_bytes());
512
for (k, v) in self.spec_constants.lock().unwrap().iter() {
513
bin.extend_from_slice(&k.to_ne_bytes());
515
// SAFETY: we fully initialize this union
516
bin.extend_from_slice(&v.u64_.to_ne_bytes());
520
Some(cache.gen_key(&bin))
526
pub fn devs_with_build(&self) -> Vec<&Arc<Device>> {
527
let mut lock = self.build_info();
531
let info = Self::dev_build_info(&mut lock, d);
532
info.status == CL_BUILD_SUCCESS as cl_build_status
537
pub fn attribute_str(&self, kernel: &str, d: &Arc<Device>) -> String {
538
let mut lock = self.build_info();
539
let info = Self::dev_build_info(&mut lock, d);
541
let attributes_strings = [
542
info.spirv.as_ref().unwrap().vec_type_hint(kernel),
543
info.spirv.as_ref().unwrap().local_size(kernel),
544
info.spirv.as_ref().unwrap().local_size_hint(kernel),
547
let attributes_strings: Vec<_> = attributes_strings
552
attributes_strings.join(",")
555
pub fn to_nir(&self, kernel: &str, d: &Arc<Device>) -> NirShader {
556
let constants = self.spec_constants.lock().unwrap();
557
let mut spec_constants: Vec<_> = constants
559
.map(|(&id, &value)| nir_spirv_specialization {
562
defined_on_module: true,
567
let mut lock = self.build_info();
569
let info = Self::dev_build_info(&mut lock, d);
570
assert_eq!(info.status, CL_BUILD_SUCCESS as cl_build_status);
572
let mut log = Platform::get().debug.program.then(Vec::new);
573
let nir = info.spirv.as_ref().unwrap().to_nir(
576
.nir_shader_compiler_options(pipe_shader_type::PIPE_SHADER_COMPUTE),
583
if let Some(log) = log {
585
eprintln!("{}", line);
695
pub fn is_bin(&self) -> bool {
696
matches!(self.src, ProgramSourceType::Binary)
592
699
pub fn is_il(&self) -> bool {