Home | History | Annotate | Download | only in api
      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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20 // SOFTWARE.
     21 //
     22 
     23 #include "api/util.hpp"
     24 #include "core/program.hpp"
     25 
     26 using namespace clover;
     27 
     28 PUBLIC cl_program
     29 clCreateProgramWithSource(cl_context ctx, cl_uint count,
     30                           const char **strings, const size_t *lengths,
     31                           cl_int *errcode_ret) try {
     32    std::string source;
     33 
     34    if (!ctx)
     35       throw error(CL_INVALID_CONTEXT);
     36 
     37    if (!count || !strings ||
     38        any_of(is_zero<const char *>(), strings, strings + count))
     39       throw error(CL_INVALID_VALUE);
     40 
     41    // Concatenate all the provided fragments together
     42    for (unsigned i = 0; i < count; ++i)
     43          source += (lengths && lengths[i] ?
     44                     std::string(strings[i], strings[i] + lengths[i]) :
     45                     std::string(strings[i]));
     46 
     47    // ...and create a program object for them.
     48    ret_error(errcode_ret, CL_SUCCESS);
     49    return new program(*ctx, source);
     50 
     51 } catch (error &e) {
     52    ret_error(errcode_ret, e);
     53    return NULL;
     54 }
     55 
     56 PUBLIC cl_program
     57 clCreateProgramWithBinary(cl_context ctx, cl_uint count,
     58                           const cl_device_id *devs, const size_t *lengths,
     59                           const unsigned char **binaries, cl_int *status_ret,
     60                           cl_int *errcode_ret) try {
     61    if (!ctx)
     62       throw error(CL_INVALID_CONTEXT);
     63 
     64    if (!count || !devs || !lengths || !binaries)
     65       throw error(CL_INVALID_VALUE);
     66 
     67    if (any_of([&](const cl_device_id dev) {
     68             return !ctx->has_device(dev);
     69          }, devs, devs + count))
     70       throw error(CL_INVALID_DEVICE);
     71 
     72    // Deserialize the provided binaries,
     73    auto modules = map(
     74       [](const unsigned char *p, size_t l) -> std::pair<cl_int, module> {
     75          if (!p || !l)
     76             return { CL_INVALID_VALUE, {} };
     77 
     78          try {
     79             compat::istream::buffer_t bin(p, l);
     80             compat::istream s(bin);
     81 
     82             return { CL_SUCCESS, module::deserialize(s) };
     83 
     84          } catch (compat::istream::error &e) {
     85             return { CL_INVALID_BINARY, {} };
     86          }
     87       },
     88       binaries, binaries + count, lengths);
     89 
     90    // update the status array,
     91    if (status_ret)
     92       std::transform(modules.begin(), modules.end(), status_ret,
     93                      keys<cl_int, module>);
     94 
     95    if (any_of(key_equals<cl_int, module>(CL_INVALID_VALUE),
     96               modules.begin(), modules.end()))
     97       throw error(CL_INVALID_VALUE);
     98 
     99    if (any_of(key_equals<cl_int, module>(CL_INVALID_BINARY),
    100               modules.begin(), modules.end()))
    101       throw error(CL_INVALID_BINARY);
    102 
    103    // initialize a program object with them.
    104    ret_error(errcode_ret, CL_SUCCESS);
    105    return new program(*ctx, { devs, devs + count },
    106                       map(values<cl_int, module>,
    107                           modules.begin(), modules.end()));
    108 
    109 } catch (error &e) {
    110    ret_error(errcode_ret, e);
    111    return NULL;
    112 }
    113 
    114 PUBLIC cl_int
    115 clRetainProgram(cl_program prog) {
    116    if (!prog)
    117       return CL_INVALID_PROGRAM;
    118 
    119    prog->retain();
    120    return CL_SUCCESS;
    121 }
    122 
    123 PUBLIC cl_int
    124 clReleaseProgram(cl_program prog) {
    125    if (!prog)
    126       return CL_INVALID_PROGRAM;
    127 
    128    if (prog->release())
    129       delete prog;
    130 
    131    return CL_SUCCESS;
    132 }
    133 
    134 PUBLIC cl_int
    135 clBuildProgram(cl_program prog, cl_uint count, const cl_device_id *devs,
    136                const char *opts, void (*pfn_notify)(cl_program, void *),
    137                void *user_data) try {
    138    if (!prog)
    139       throw error(CL_INVALID_PROGRAM);
    140 
    141    if (bool(count) != bool(devs) ||
    142        (!pfn_notify && user_data))
    143       throw error(CL_INVALID_VALUE);
    144 
    145    if (devs) {
    146       if (any_of([&](const cl_device_id dev) {
    147                return !prog->ctx.has_device(dev);
    148             }, devs, devs + count))
    149          throw error(CL_INVALID_DEVICE);
    150 
    151       prog->build({ devs, devs + count });
    152    } else {
    153       prog->build(prog->ctx.devs);
    154    }
    155 
    156    return CL_SUCCESS;
    157 
    158 } catch (error &e) {
    159    return e.get();
    160 }
    161 
    162 PUBLIC cl_int
    163 clUnloadCompiler() {
    164    return CL_SUCCESS;
    165 }
    166 
    167 PUBLIC cl_int
    168 clGetProgramInfo(cl_program prog, cl_program_info param,
    169                  size_t size, void *buf, size_t *size_ret) {
    170    if (!prog)
    171       return CL_INVALID_PROGRAM;
    172 
    173    switch (param) {
    174    case CL_PROGRAM_REFERENCE_COUNT:
    175       return scalar_property<cl_uint>(buf, size, size_ret,
    176                                       prog->ref_count());
    177 
    178    case CL_PROGRAM_CONTEXT:
    179       return scalar_property<cl_context>(buf, size, size_ret,
    180                                          &prog->ctx);
    181 
    182    case CL_PROGRAM_NUM_DEVICES:
    183       return scalar_property<cl_uint>(buf, size, size_ret,
    184                                       prog->binaries().size());
    185 
    186    case CL_PROGRAM_DEVICES:
    187       return vector_property<cl_device_id>(
    188          buf, size, size_ret,
    189          map(keys<device *, module>,
    190              prog->binaries().begin(), prog->binaries().end()));
    191 
    192    case CL_PROGRAM_SOURCE:
    193       return string_property(buf, size, size_ret, prog->source());
    194 
    195    case CL_PROGRAM_BINARY_SIZES:
    196       return vector_property<size_t>(
    197          buf, size, size_ret,
    198          map([](const std::pair<device *, module> &ent) {
    199                compat::ostream::buffer_t bin;
    200                compat::ostream s(bin);
    201                ent.second.serialize(s);
    202                return bin.size();
    203             },
    204             prog->binaries().begin(), prog->binaries().end()));
    205 
    206    case CL_PROGRAM_BINARIES:
    207       return matrix_property<unsigned char>(
    208          buf, size, size_ret,
    209          map([](const std::pair<device *, module> &ent) {
    210                compat::ostream::buffer_t bin;
    211                compat::ostream s(bin);
    212                ent.second.serialize(s);
    213                return bin;
    214             },
    215             prog->binaries().begin(), prog->binaries().end()));
    216 
    217    default:
    218       return CL_INVALID_VALUE;
    219    }
    220 }
    221 
    222 PUBLIC cl_int
    223 clGetProgramBuildInfo(cl_program prog, cl_device_id dev,
    224                       cl_program_build_info param,
    225                       size_t size, void *buf, size_t *size_ret) {
    226    if (!prog)
    227       return CL_INVALID_PROGRAM;
    228 
    229    if (!prog->ctx.has_device(dev))
    230       return CL_INVALID_DEVICE;
    231 
    232    switch (param) {
    233    case CL_PROGRAM_BUILD_STATUS:
    234       return scalar_property<cl_build_status>(buf, size, size_ret,
    235                                               prog->build_status(dev));
    236 
    237    case CL_PROGRAM_BUILD_OPTIONS:
    238       return string_property(buf, size, size_ret, prog->build_opts(dev));
    239 
    240    case CL_PROGRAM_BUILD_LOG:
    241       return string_property(buf, size, size_ret, prog->build_log(dev));
    242 
    243    default:
    244       return CL_INVALID_VALUE;
    245    }
    246 }
    247