File indexing completed on 2025-01-18 09:30:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_COMPUTE_PROGRAM_HPP
0012 #define BOOST_COMPUTE_PROGRAM_HPP
0013
0014 #include <string>
0015 #include <vector>
0016 #include <fstream>
0017 #include <streambuf>
0018
0019 #ifdef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
0020 #include <iostream>
0021 #endif
0022
0023 #include <boost/compute/config.hpp>
0024 #include <boost/compute/context.hpp>
0025 #include <boost/compute/exception.hpp>
0026 #include <boost/compute/exception/program_build_failure.hpp>
0027 #include <boost/compute/detail/assert_cl_success.hpp>
0028
0029 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0030 #include <sstream>
0031 #include <boost/optional.hpp>
0032 #include <boost/compute/platform.hpp>
0033 #include <boost/compute/detail/getenv.hpp>
0034 #include <boost/compute/detail/path.hpp>
0035 #include <boost/compute/detail/sha1.hpp>
0036 #endif
0037
0038 namespace boost {
0039 namespace compute {
0040
0041 class kernel;
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 class program
0075 {
0076 public:
0077
0078 program()
0079 : m_program(0)
0080 {
0081 }
0082
0083
0084
0085 explicit program(cl_program program, bool retain = true)
0086 : m_program(program)
0087 {
0088 if(m_program && retain){
0089 clRetainProgram(m_program);
0090 }
0091 }
0092
0093
0094 program(const program &other)
0095 : m_program(other.m_program)
0096 {
0097 if(m_program){
0098 clRetainProgram(m_program);
0099 }
0100 }
0101
0102
0103 program& operator=(const program &other)
0104 {
0105 if(this != &other){
0106 if(m_program){
0107 clReleaseProgram(m_program);
0108 }
0109
0110 m_program = other.m_program;
0111
0112 if(m_program){
0113 clRetainProgram(m_program);
0114 }
0115 }
0116
0117 return *this;
0118 }
0119
0120 #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
0121
0122 program(program&& other) BOOST_NOEXCEPT
0123 : m_program(other.m_program)
0124 {
0125 other.m_program = 0;
0126 }
0127
0128
0129 program& operator=(program&& other) BOOST_NOEXCEPT
0130 {
0131 if(m_program){
0132 clReleaseProgram(m_program);
0133 }
0134
0135 m_program = other.m_program;
0136 other.m_program = 0;
0137
0138 return *this;
0139 }
0140 #endif
0141
0142
0143 ~program()
0144 {
0145 if(m_program){
0146 BOOST_COMPUTE_ASSERT_CL_SUCCESS(
0147 clReleaseProgram(m_program)
0148 );
0149 }
0150 }
0151
0152
0153 cl_program& get() const
0154 {
0155 return const_cast<cl_program &>(m_program);
0156 }
0157
0158
0159 std::string source() const
0160 {
0161 return get_info<std::string>(CL_PROGRAM_SOURCE);
0162 }
0163
0164
0165 std::vector<unsigned char> binary() const
0166 {
0167 size_t binary_size = get_info<size_t>(CL_PROGRAM_BINARY_SIZES);
0168 std::vector<unsigned char> binary(binary_size);
0169
0170 unsigned char *binary_ptr = &binary[0];
0171 cl_int error = clGetProgramInfo(m_program,
0172 CL_PROGRAM_BINARIES,
0173 sizeof(unsigned char **),
0174 &binary_ptr,
0175 0);
0176 if(error != CL_SUCCESS){
0177 BOOST_THROW_EXCEPTION(opencl_error(error));
0178 }
0179
0180 return binary;
0181 }
0182
0183 #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0184
0185 std::vector<unsigned char> il_binary() const
0186 {
0187 return get_info<std::vector<unsigned char> >(CL_PROGRAM_IL);
0188 }
0189 #endif
0190
0191 std::vector<device> get_devices() const
0192 {
0193 std::vector<cl_device_id> device_ids =
0194 get_info<std::vector<cl_device_id> >(CL_PROGRAM_DEVICES);
0195
0196 std::vector<device> devices;
0197 for(size_t i = 0; i < device_ids.size(); i++){
0198 devices.push_back(device(device_ids[i]));
0199 }
0200
0201 return devices;
0202 }
0203
0204
0205 context get_context() const
0206 {
0207 return context(get_info<cl_context>(CL_PROGRAM_CONTEXT));
0208 }
0209
0210
0211
0212
0213 template<class T>
0214 T get_info(cl_program_info info) const
0215 {
0216 return detail::get_object_info<T>(clGetProgramInfo, m_program, info);
0217 }
0218
0219
0220 template<int Enum>
0221 typename detail::get_object_info_type<program, Enum>::type
0222 get_info() const;
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 template<class T>
0235 T get_build_info(cl_program_build_info info, const device &device) const
0236 {
0237 return detail::get_object_info<T>(clGetProgramBuildInfo, m_program, info, device.id());
0238 }
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256 void build(const std::string &options = std::string())
0257 {
0258 const char *options_string = 0;
0259
0260 if(!options.empty()){
0261 options_string = options.c_str();
0262 }
0263
0264 cl_int ret = clBuildProgram(m_program, 0, 0, options_string, 0, 0);
0265
0266 #ifdef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
0267 if(ret != CL_SUCCESS){
0268
0269 std::cerr << "Boost.Compute: "
0270 << "kernel compilation failed (" << ret << ")\n"
0271 << "--- source ---\n"
0272 << source()
0273 << "\n--- build log ---\n"
0274 << build_log()
0275 << std::endl;
0276 }
0277 #endif
0278
0279 if(ret != CL_SUCCESS){
0280 BOOST_THROW_EXCEPTION(program_build_failure(ret, build_log()));
0281 }
0282 }
0283
0284 #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0285
0286
0287
0288
0289
0290 void compile(const std::string &options = std::string(),
0291 const std::vector<std::pair<std::string, program> > &headers =
0292 std::vector<std::pair<std::string, program> >())
0293 {
0294 const char *options_string = 0;
0295
0296 if(!options.empty()){
0297 options_string = options.c_str();
0298 }
0299
0300 cl_int ret;
0301 if (headers.empty())
0302 {
0303 ret = clCompileProgram(
0304 m_program, 0, 0, options_string, 0, 0, 0, 0, 0
0305 );
0306 }
0307 else
0308 {
0309 std::vector<const char*> header_names(headers.size());
0310 std::vector<cl_program> header_programs(headers.size());
0311 for (size_t i = 0; i < headers.size(); ++i)
0312 {
0313 header_names[i] = headers[i].first.c_str();
0314 header_programs[i] = headers[i].second.m_program;
0315 }
0316
0317 ret = clCompileProgram(
0318 m_program,
0319 0,
0320 0,
0321 options_string,
0322 static_cast<cl_uint>(headers.size()),
0323 header_programs.data(),
0324 header_names.data(),
0325 0,
0326 0
0327 );
0328 }
0329
0330 if(ret != CL_SUCCESS){
0331 BOOST_THROW_EXCEPTION(opencl_error(ret));
0332 }
0333 }
0334
0335
0336
0337
0338
0339
0340 static program link(const std::vector<program> &programs,
0341 const context &context,
0342 const std::string &options = std::string())
0343 {
0344 const char *options_string = 0;
0345
0346 if(!options.empty()){
0347 options_string = options.c_str();
0348 }
0349
0350 cl_int ret;
0351 cl_program program_ = clLinkProgram(
0352 context.get(),
0353 0,
0354 0,
0355 options_string,
0356 static_cast<uint_>(programs.size()),
0357 reinterpret_cast<const cl_program*>(&programs[0]),
0358 0,
0359 0,
0360 &ret
0361 );
0362
0363 if(!program_){
0364 BOOST_THROW_EXCEPTION(opencl_error(ret));
0365 }
0366
0367 return program(program_, false);
0368 }
0369 #endif
0370
0371
0372 std::string build_log() const
0373 {
0374 return get_build_info<std::string>(CL_PROGRAM_BUILD_LOG, get_devices().front());
0375 }
0376
0377
0378
0379
0380
0381
0382
0383
0384 kernel create_kernel(const std::string &name) const;
0385
0386
0387 bool operator==(const program &other) const
0388 {
0389 return m_program == other.m_program;
0390 }
0391
0392
0393 bool operator!=(const program &other) const
0394 {
0395 return m_program != other.m_program;
0396 }
0397
0398
0399 operator cl_program() const
0400 {
0401 return m_program;
0402 }
0403
0404
0405
0406
0407 static program create_with_source(const std::string &source,
0408 const context &context)
0409 {
0410 const char *source_string = source.c_str();
0411
0412 cl_int error = 0;
0413 cl_program program_ = clCreateProgramWithSource(context,
0414 uint_(1),
0415 &source_string,
0416 0,
0417 &error);
0418 if(!program_){
0419 BOOST_THROW_EXCEPTION(opencl_error(error));
0420 }
0421
0422 return program(program_, false);
0423 }
0424
0425
0426
0427
0428 static program create_with_source(const std::vector<std::string> &sources,
0429 const context &context)
0430 {
0431 std::vector<const char*> source_strings(sources.size());
0432 for(size_t i = 0; i < sources.size(); i++){
0433 source_strings[i] = sources[i].c_str();
0434 }
0435
0436 cl_int error = 0;
0437 cl_program program_ = clCreateProgramWithSource(context,
0438 uint_(sources.size()),
0439 &source_strings[0],
0440 0,
0441 &error);
0442 if(!program_){
0443 BOOST_THROW_EXCEPTION(opencl_error(error));
0444 }
0445
0446 return program(program_, false);
0447 }
0448
0449
0450
0451
0452 static program create_with_source_file(const std::string &file,
0453 const context &context)
0454 {
0455
0456 return create_with_source(read_source_file(file), context);
0457 }
0458
0459
0460
0461
0462 static program create_with_source_file(const std::vector<std::string> &files,
0463 const context &context)
0464 {
0465 std::vector<std::string> sources(files.size());
0466
0467 for(size_t i = 0; i < files.size(); ++i) {
0468
0469 std::ifstream stream(files[i].c_str());
0470
0471 if(stream.fail()){
0472 BOOST_THROW_EXCEPTION(std::ios_base::failure("failed to create stream."));
0473 }
0474
0475
0476 sources[i] = std::string(
0477 (std::istreambuf_iterator<char>(stream)),
0478 std::istreambuf_iterator<char>()
0479 );
0480 }
0481
0482
0483 return create_with_source(sources, context);
0484 }
0485
0486
0487
0488
0489
0490 static program create_with_binary(const unsigned char *binary,
0491 size_t binary_size,
0492 const context &context)
0493 {
0494 const cl_device_id device = context.get_device().id();
0495
0496 cl_int error = 0;
0497 cl_int binary_status = 0;
0498 cl_program program_ = clCreateProgramWithBinary(context,
0499 uint_(1),
0500 &device,
0501 &binary_size,
0502 &binary,
0503 &binary_status,
0504 &error);
0505 if(!program_){
0506 BOOST_THROW_EXCEPTION(opencl_error(error));
0507 }
0508 if(binary_status != CL_SUCCESS){
0509 BOOST_THROW_EXCEPTION(opencl_error(binary_status));
0510 }
0511
0512 return program(program_, false);
0513 }
0514
0515
0516
0517
0518 static program create_with_binary(const std::vector<unsigned char> &binary,
0519 const context &context)
0520 {
0521 return create_with_binary(&binary[0], binary.size(), context);
0522 }
0523
0524
0525
0526
0527 static program create_with_binary_file(const std::string &file,
0528 const context &context)
0529 {
0530
0531 std::ifstream stream(file.c_str(), std::ios::in | std::ios::binary);
0532
0533
0534 std::vector<unsigned char> binary(
0535 (std::istreambuf_iterator<char>(stream)),
0536 std::istreambuf_iterator<char>()
0537 );
0538
0539
0540 return create_with_binary(&binary[0], binary.size(), context);
0541 }
0542
0543 #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0544
0545
0546
0547
0548
0549
0550 static program create_with_builtin_kernels(const context &context,
0551 const std::vector<device> &devices,
0552 const std::string &kernel_names)
0553 {
0554 cl_int error = 0;
0555
0556 cl_program program_ = clCreateProgramWithBuiltInKernels(
0557 context.get(),
0558 static_cast<uint_>(devices.size()),
0559 reinterpret_cast<const cl_device_id *>(&devices[0]),
0560 kernel_names.c_str(),
0561 &error
0562 );
0563
0564 if(!program_){
0565 BOOST_THROW_EXCEPTION(opencl_error(error));
0566 }
0567
0568 return program(program_, false);
0569 }
0570 #endif
0571
0572 #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0573
0574
0575
0576
0577
0578
0579 static program create_with_il(const void * il_binary,
0580 const size_t il_size,
0581 const context &context)
0582 {
0583 cl_int error = 0;
0584
0585 cl_program program_ = clCreateProgramWithIL(
0586 context.get(), il_binary, il_size, &error
0587 );
0588
0589 if(!program_){
0590 BOOST_THROW_EXCEPTION(opencl_error(error));
0591 }
0592
0593 return program(program_, false);
0594 }
0595
0596
0597
0598
0599
0600
0601
0602 static program create_with_il(const std::vector<unsigned char> &il_binary,
0603 const context &context)
0604 {
0605 return create_with_il(&il_binary[0], il_binary.size(), context);
0606 }
0607
0608
0609
0610
0611
0612
0613
0614 static program create_with_il_file(const std::string &file,
0615 const context &context)
0616 {
0617
0618 std::ifstream stream(file.c_str(), std::ios::in | std::ios::binary);
0619
0620
0621 std::vector<unsigned char> il(
0622 (std::istreambuf_iterator<char>(stream)),
0623 std::istreambuf_iterator<char>()
0624 );
0625
0626
0627 return create_with_il(&il[0], il.size(), context);
0628 }
0629 #endif
0630
0631
0632
0633
0634
0635
0636
0637
0638 static program build_with_source(
0639 const std::string &source,
0640 const context &context,
0641 const std::string &options = std::string()
0642 )
0643 {
0644 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0645
0646 device d = context.get_device();
0647 platform p = d.platform();
0648
0649 detail::sha1 hash;
0650 hash.process( p.name() )
0651 .process( p.version() )
0652 .process( d.name() )
0653 .process( options )
0654 .process( source )
0655 ;
0656 std::string hash_string = hash;
0657
0658
0659 try {
0660 boost::optional<program> prog = load_program_binary(hash_string, context);
0661
0662 if (prog) {
0663 prog->build(options);
0664 return *prog;
0665 }
0666 } catch (...) {
0667
0668 }
0669
0670
0671 #endif
0672 const char *source_string = source.c_str();
0673
0674 cl_int error = 0;
0675 cl_program program_ = clCreateProgramWithSource(context,
0676 uint_(1),
0677 &source_string,
0678 0,
0679 &error);
0680 if(!program_){
0681 BOOST_THROW_EXCEPTION(opencl_error(error));
0682 }
0683
0684 program prog(program_, false);
0685 prog.build(options);
0686
0687 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0688
0689 save_program_binary(hash_string, prog);
0690 #endif
0691
0692 return prog;
0693 }
0694
0695
0696
0697
0698
0699
0700
0701
0702 static program build_with_source_file(
0703 const std::string &file,
0704 const context &context,
0705 const std::string &options = std::string()
0706 )
0707 {
0708 return build_with_source(read_source_file(file), context, options);
0709 }
0710
0711 private:
0712 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0713
0714 static void save_program_binary(const std::string &hash, const program &prog)
0715 {
0716 std::string fname = detail::program_binary_path(hash, true) + "kernel";
0717 std::ofstream bfile(fname.c_str(), std::ios::binary);
0718 if (!bfile) return;
0719
0720 std::vector<unsigned char> binary = prog.binary();
0721
0722 size_t binary_size = binary.size();
0723 bfile.write((char*)&binary_size, sizeof(size_t));
0724 bfile.write((char*)binary.data(), binary_size);
0725 }
0726
0727
0728 static boost::optional<program> load_program_binary(
0729 const std::string &hash, const context &ctx
0730 )
0731 {
0732 std::string fname = detail::program_binary_path(hash) + "kernel";
0733 std::ifstream bfile(fname.c_str(), std::ios::binary);
0734 if (!bfile) return boost::optional<program>();
0735
0736 size_t binary_size;
0737 std::vector<unsigned char> binary;
0738
0739 bfile.read((char*)&binary_size, sizeof(size_t));
0740
0741 binary.resize(binary_size);
0742 bfile.read((char*)binary.data(), binary_size);
0743
0744 return boost::optional<program>(
0745 program::create_with_binary(
0746 binary.data(), binary_size, ctx
0747 )
0748 );
0749 }
0750 #endif
0751
0752 static std::string read_source_file(const std::string &file)
0753 {
0754
0755 std::ifstream stream(file.c_str());
0756
0757 if(stream.fail()){
0758 BOOST_THROW_EXCEPTION(std::ios_base::failure("failed to create stream."));
0759 }
0760
0761
0762 return std::string(
0763 (std::istreambuf_iterator<char>(stream)),
0764 std::istreambuf_iterator<char>()
0765 );
0766 }
0767
0768 private:
0769 cl_program m_program;
0770 };
0771
0772
0773 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
0774 ((cl_uint, CL_PROGRAM_REFERENCE_COUNT))
0775 ((cl_context, CL_PROGRAM_CONTEXT))
0776 ((cl_uint, CL_PROGRAM_NUM_DEVICES))
0777 ((std::vector<cl_device_id>, CL_PROGRAM_DEVICES))
0778 ((std::string, CL_PROGRAM_SOURCE))
0779 ((std::vector<size_t>, CL_PROGRAM_BINARY_SIZES))
0780 ((std::vector<unsigned char *>, CL_PROGRAM_BINARIES))
0781 )
0782
0783 #ifdef BOOST_COMPUTE_CL_VERSION_1_2
0784 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
0785 ((size_t, CL_PROGRAM_NUM_KERNELS))
0786 ((std::string, CL_PROGRAM_KERNEL_NAMES))
0787 )
0788 #endif
0789
0790 #ifdef BOOST_COMPUTE_CL_VERSION_2_1
0791 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
0792 ((std::vector<unsigned char>, CL_PROGRAM_IL))
0793 )
0794 #endif
0795
0796 }
0797 }
0798
0799 #endif