Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. //
  2. // Copyright 2012 Francisco Jerez
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a
  5. // copy of this software and associated documentation files (the "Software"),
  6. // to deal in the Software without restriction, including without limitation
  7. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. // and/or sell copies of the Software, and to permit persons to whom the
  9. // Software is furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17. // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. // OTHER DEALINGS IN THE SOFTWARE.
  21. //
  22.  
  23. #include "api/util.hpp"
  24. #include "core/program.hpp"
  25.  
  26. #include <sstream>
  27.  
  28. using namespace clover;
  29.  
  30. namespace {
  31.    void validate_build_program_common(const program &prog, cl_uint num_devs,
  32.                                       const cl_device_id *d_devs,
  33.                                       void (*pfn_notify)(cl_program, void *),
  34.                                       void *user_data) {
  35.  
  36.       if ((!pfn_notify && user_data))
  37.          throw error(CL_INVALID_VALUE);
  38.  
  39.       if (prog.kernel_ref_count())
  40.          throw error(CL_INVALID_OPERATION);
  41.  
  42.       if (any_of([&](const device &dev) {
  43.                return !count(dev, prog.context().devices());
  44.             }, objs<allow_empty_tag>(d_devs, num_devs)))
  45.          throw error(CL_INVALID_DEVICE);
  46.    }
  47. }
  48.  
  49. CLOVER_API cl_program
  50. clCreateProgramWithSource(cl_context d_ctx, cl_uint count,
  51.                           const char **strings, const size_t *lengths,
  52.                           cl_int *r_errcode) try {
  53.    auto &ctx = obj(d_ctx);
  54.    std::string source;
  55.  
  56.    if (!count || !strings ||
  57.        any_of(is_zero(), range(strings, count)))
  58.       throw error(CL_INVALID_VALUE);
  59.  
  60.    // Concatenate all the provided fragments together
  61.    for (unsigned i = 0; i < count; ++i)
  62.          source += (lengths && lengths[i] ?
  63.                     std::string(strings[i], strings[i] + lengths[i]) :
  64.                     std::string(strings[i]));
  65.  
  66.    // ...and create a program object for them.
  67.    ret_error(r_errcode, CL_SUCCESS);
  68.    return new program(ctx, source);
  69.  
  70. } catch (error &e) {
  71.    ret_error(r_errcode, e);
  72.    return NULL;
  73. }
  74.  
  75. CLOVER_API cl_program
  76. clCreateProgramWithBinary(cl_context d_ctx, cl_uint n,
  77.                           const cl_device_id *d_devs,
  78.                           const size_t *lengths,
  79.                           const unsigned char **binaries,
  80.                           cl_int *r_status, cl_int *r_errcode) try {
  81.    auto &ctx = obj(d_ctx);
  82.    auto devs = objs(d_devs, n);
  83.  
  84.    if (!lengths || !binaries)
  85.       throw error(CL_INVALID_VALUE);
  86.  
  87.    if (any_of([&](const device &dev) {
  88.             return !count(dev, ctx.devices());
  89.          }, devs))
  90.       throw error(CL_INVALID_DEVICE);
  91.  
  92.    // Deserialize the provided binaries,
  93.    std::vector<std::pair<cl_int, module>> result = map(
  94.       [](const unsigned char *p, size_t l) -> std::pair<cl_int, module> {
  95.          if (!p || !l)
  96.             return { CL_INVALID_VALUE, {} };
  97.  
  98.          try {
  99.             std::stringbuf bin( { (char*)p, l } );
  100.             std::istream s(&bin);
  101.  
  102.             return { CL_SUCCESS, module::deserialize(s) };
  103.  
  104.          } catch (std::istream::failure &e) {
  105.             return { CL_INVALID_BINARY, {} };
  106.          }
  107.       },
  108.       range(binaries, n),
  109.       range(lengths, n));
  110.  
  111.    // update the status array,
  112.    if (r_status)
  113.       copy(map(keys(), result), r_status);
  114.  
  115.    if (any_of(key_equals(CL_INVALID_VALUE), result))
  116.       throw error(CL_INVALID_VALUE);
  117.  
  118.    if (any_of(key_equals(CL_INVALID_BINARY), result))
  119.       throw error(CL_INVALID_BINARY);
  120.  
  121.    // initialize a program object with them.
  122.    ret_error(r_errcode, CL_SUCCESS);
  123.    return new program(ctx, devs, map(values(), result));
  124.  
  125. } catch (error &e) {
  126.    ret_error(r_errcode, e);
  127.    return NULL;
  128. }
  129.  
  130. CLOVER_API cl_program
  131. clCreateProgramWithBuiltInKernels(cl_context d_ctx, cl_uint n,
  132.                                   const cl_device_id *d_devs,
  133.                                   const char *kernel_names,
  134.                                   cl_int *r_errcode) try {
  135.    auto &ctx = obj(d_ctx);
  136.    auto devs = objs(d_devs, n);
  137.  
  138.    if (any_of([&](const device &dev) {
  139.             return !count(dev, ctx.devices());
  140.          }, devs))
  141.       throw error(CL_INVALID_DEVICE);
  142.  
  143.    // No currently supported built-in kernels.
  144.    throw error(CL_INVALID_VALUE);
  145.  
  146. } catch (error &e) {
  147.    ret_error(r_errcode, e);
  148.    return NULL;
  149. }
  150.  
  151.  
  152. CLOVER_API cl_int
  153. clRetainProgram(cl_program d_prog) try {
  154.    obj(d_prog).retain();
  155.    return CL_SUCCESS;
  156.  
  157. } catch (error &e) {
  158.    return e.get();
  159. }
  160.  
  161. CLOVER_API cl_int
  162. clReleaseProgram(cl_program d_prog) try {
  163.    if (obj(d_prog).release())
  164.       delete pobj(d_prog);
  165.  
  166.    return CL_SUCCESS;
  167.  
  168. } catch (error &e) {
  169.    return e.get();
  170. }
  171.  
  172. CLOVER_API cl_int
  173. clBuildProgram(cl_program d_prog, cl_uint num_devs,
  174.                const cl_device_id *d_devs, const char *p_opts,
  175.                void (*pfn_notify)(cl_program, void *),
  176.                void *user_data) try {
  177.    auto &prog = obj(d_prog);
  178.    auto devs = (d_devs ? objs(d_devs, num_devs) :
  179.                 ref_vector<device>(prog.context().devices()));
  180.    auto opts = (p_opts ? p_opts : "");
  181.  
  182.    validate_build_program_common(prog, num_devs, d_devs, pfn_notify, user_data);
  183.  
  184.    prog.build(devs, opts);
  185.    return CL_SUCCESS;
  186. } catch (error &e) {
  187.    if (e.get() == CL_INVALID_COMPILER_OPTIONS)
  188.       return CL_INVALID_BUILD_OPTIONS;
  189.    if (e.get() == CL_COMPILE_PROGRAM_FAILURE)
  190.       return CL_BUILD_PROGRAM_FAILURE;
  191.    return e.get();
  192. }
  193.  
  194. CLOVER_API cl_int
  195. clCompileProgram(cl_program d_prog, cl_uint num_devs,
  196.                  const cl_device_id *d_devs, const char *p_opts,
  197.                  cl_uint num_headers, const cl_program *d_header_progs,
  198.                  const char **header_names,
  199.                  void (*pfn_notify)(cl_program, void *),
  200.                  void *user_data) try {
  201.    auto &prog = obj(d_prog);
  202.    auto devs = (d_devs ? objs(d_devs, num_devs) :
  203.                 ref_vector<device>(prog.context().devices()));
  204.    auto opts = (p_opts ? p_opts : "");
  205.    header_map headers;
  206.  
  207.    validate_build_program_common(prog, num_devs, d_devs, pfn_notify, user_data);
  208.  
  209.    if (bool(num_headers) != bool(header_names))
  210.       throw error(CL_INVALID_VALUE);
  211.  
  212.    if (!prog.has_source)
  213.       throw error(CL_INVALID_OPERATION);
  214.  
  215.  
  216.    for_each([&](const char *name, const program &header) {
  217.          if (!header.has_source)
  218.             throw error(CL_INVALID_OPERATION);
  219.  
  220.          if (!any_of(key_equals(name), headers))
  221.             headers.push_back(std::pair<std::string, std::string>(
  222.                                  name, header.source()));
  223.       },
  224.       range(header_names, num_headers),
  225.       objs<allow_empty_tag>(d_header_progs, num_headers));
  226.  
  227.    prog.build(devs, opts, headers);
  228.    return CL_SUCCESS;
  229.  
  230. } catch (error &e) {
  231.    return e.get();
  232. }
  233.  
  234. CLOVER_API cl_int
  235. clUnloadCompiler() {
  236.    return CL_SUCCESS;
  237. }
  238.  
  239. CLOVER_API cl_int
  240. clUnloadPlatformCompiler(cl_platform_id d_platform) {
  241.    return CL_SUCCESS;
  242. }
  243.  
  244. CLOVER_API cl_int
  245. clGetProgramInfo(cl_program d_prog, cl_program_info param,
  246.                  size_t size, void *r_buf, size_t *r_size) try {
  247.    property_buffer buf { r_buf, size, r_size };
  248.    auto &prog = obj(d_prog);
  249.  
  250.    switch (param) {
  251.    case CL_PROGRAM_REFERENCE_COUNT:
  252.       buf.as_scalar<cl_uint>() = prog.ref_count();
  253.       break;
  254.  
  255.    case CL_PROGRAM_CONTEXT:
  256.       buf.as_scalar<cl_context>() = desc(prog.context());
  257.       break;
  258.  
  259.    case CL_PROGRAM_NUM_DEVICES:
  260.       buf.as_scalar<cl_uint>() = (prog.devices().size() ?
  261.                                   prog.devices().size() :
  262.                                   prog.context().devices().size());
  263.       break;
  264.  
  265.    case CL_PROGRAM_DEVICES:
  266.       buf.as_vector<cl_device_id>() = (prog.devices().size() ?
  267.                                        descs(prog.devices()) :
  268.                                        descs(prog.context().devices()));
  269.       break;
  270.  
  271.    case CL_PROGRAM_SOURCE:
  272.       buf.as_string() = prog.source();
  273.       break;
  274.  
  275.    case CL_PROGRAM_BINARY_SIZES:
  276.       buf.as_vector<size_t>() = map([&](const device &dev) {
  277.             return prog.binary(dev).size();
  278.          },
  279.          prog.devices());
  280.       break;
  281.  
  282.    case CL_PROGRAM_BINARIES:
  283.       buf.as_matrix<unsigned char>() = map([&](const device &dev) {
  284.             std::stringbuf bin;
  285.             std::ostream s(&bin);
  286.             prog.binary(dev).serialize(s);
  287.             return bin.str();
  288.          },
  289.          prog.devices());
  290.       break;
  291.  
  292.    case CL_PROGRAM_NUM_KERNELS:
  293.       buf.as_scalar<cl_uint>() = prog.symbols().size();
  294.       break;
  295.  
  296.    case CL_PROGRAM_KERNEL_NAMES:
  297.       buf.as_string() = fold([](const std::string &a, const module::symbol &s) {
  298.             return ((a.empty() ? "" : a + ";") + s.name);
  299.          }, std::string(), prog.symbols());
  300.       break;
  301.  
  302.    default:
  303.       throw error(CL_INVALID_VALUE);
  304.    }
  305.  
  306.    return CL_SUCCESS;
  307.  
  308. } catch (error &e) {
  309.    return e.get();
  310. }
  311.  
  312. CLOVER_API cl_int
  313. clGetProgramBuildInfo(cl_program d_prog, cl_device_id d_dev,
  314.                       cl_program_build_info param,
  315.                       size_t size, void *r_buf, size_t *r_size) try {
  316.    property_buffer buf { r_buf, size, r_size };
  317.    auto &prog = obj(d_prog);
  318.    auto &dev = obj(d_dev);
  319.  
  320.    if (!count(dev, prog.context().devices()))
  321.       return CL_INVALID_DEVICE;
  322.  
  323.    switch (param) {
  324.    case CL_PROGRAM_BUILD_STATUS:
  325.       buf.as_scalar<cl_build_status>() = prog.build_status(dev);
  326.       break;
  327.  
  328.    case CL_PROGRAM_BUILD_OPTIONS:
  329.       buf.as_string() = prog.build_opts(dev);
  330.       break;
  331.  
  332.    case CL_PROGRAM_BUILD_LOG:
  333.       buf.as_string() = prog.build_log(dev);
  334.       break;
  335.  
  336.    default:
  337.       throw error(CL_INVALID_VALUE);
  338.    }
  339.  
  340.    return CL_SUCCESS;
  341.  
  342. } catch (error &e) {
  343.    return e.get();
  344. }
  345.