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 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 "util/u_math.h"
     24 #include "api/util.hpp"
     25 #include "core/memory.hpp"
     26 #include "core/format.hpp"
     27 
     28 using namespace clover;
     29 
     30 namespace {
     31    cl_mem_flags
     32    validate_flags(cl_mem d_parent, cl_mem_flags d_flags) {
     33       const cl_mem_flags dev_access_flags =
     34          CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY;
     35       const cl_mem_flags host_ptr_flags =
     36          CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR;
     37       const cl_mem_flags host_access_flags =
     38          CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS;
     39       const cl_mem_flags valid_flags =
     40          dev_access_flags | host_access_flags | (d_parent ? 0 : host_ptr_flags);
     41 
     42       if ((d_flags & ~valid_flags) ||
     43           util_bitcount(d_flags & dev_access_flags) > 1 ||
     44           util_bitcount(d_flags & host_access_flags) > 1)
     45          throw error(CL_INVALID_VALUE);
     46 
     47       if ((d_flags & CL_MEM_USE_HOST_PTR) &&
     48           (d_flags & (CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR)))
     49          throw error(CL_INVALID_VALUE);
     50 
     51       if (d_parent) {
     52          const auto &parent = obj(d_parent);
     53          const cl_mem_flags flags = (d_flags |
     54                                      (d_flags & dev_access_flags ? 0 :
     55                                       parent.flags() & dev_access_flags) |
     56                                      (d_flags & host_access_flags ? 0 :
     57                                       parent.flags() & host_access_flags) |
     58                                      (parent.flags() & host_ptr_flags));
     59 
     60          if (~flags & parent.flags() &
     61              ((dev_access_flags & ~CL_MEM_READ_WRITE) | host_access_flags))
     62             throw error(CL_INVALID_VALUE);
     63 
     64          return flags;
     65 
     66       } else {
     67          return d_flags | (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE);
     68       }
     69    }
     70 }
     71 
     72 CLOVER_API cl_mem
     73 clCreateBuffer(cl_context d_ctx, cl_mem_flags d_flags, size_t size,
     74                void *host_ptr, cl_int *r_errcode) try {
     75    const cl_mem_flags flags = validate_flags(NULL, d_flags);
     76    auto &ctx = obj(d_ctx);
     77 
     78    if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
     79                                        CL_MEM_COPY_HOST_PTR)))
     80       throw error(CL_INVALID_HOST_PTR);
     81 
     82    if (!size ||
     83        size > fold(maximum(), cl_ulong(0),
     84                    map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())
     85           ))
     86       throw error(CL_INVALID_BUFFER_SIZE);
     87 
     88    ret_error(r_errcode, CL_SUCCESS);
     89    return new root_buffer(ctx, flags, size, host_ptr);
     90 
     91 } catch (error &e) {
     92    ret_error(r_errcode, e);
     93    return NULL;
     94 }
     95 
     96 CLOVER_API cl_mem
     97 clCreateSubBuffer(cl_mem d_mem, cl_mem_flags d_flags,
     98                   cl_buffer_create_type op,
     99                   const void *op_info, cl_int *r_errcode) try {
    100    auto &parent = obj<root_buffer>(d_mem);
    101    const cl_mem_flags flags = validate_flags(d_mem, d_flags);
    102 
    103    if (op == CL_BUFFER_CREATE_TYPE_REGION) {
    104       auto reg = reinterpret_cast<const cl_buffer_region *>(op_info);
    105 
    106       if (!reg ||
    107           reg->origin > parent.size() ||
    108           reg->origin + reg->size > parent.size())
    109          throw error(CL_INVALID_VALUE);
    110 
    111       if (!reg->size)
    112          throw error(CL_INVALID_BUFFER_SIZE);
    113 
    114       ret_error(r_errcode, CL_SUCCESS);
    115       return new sub_buffer(parent, flags, reg->origin, reg->size);
    116 
    117    } else {
    118       throw error(CL_INVALID_VALUE);
    119    }
    120 
    121 } catch (error &e) {
    122    ret_error(r_errcode, e);
    123    return NULL;
    124 }
    125 
    126 CLOVER_API cl_mem
    127 clCreateImage(cl_context d_ctx, cl_mem_flags d_flags,
    128               const cl_image_format *format,
    129               const cl_image_desc *desc,
    130               void *host_ptr, cl_int *r_errcode) try {
    131    auto &ctx = obj(d_ctx);
    132 
    133    if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
    134       throw error(CL_INVALID_OPERATION);
    135 
    136    if (!format)
    137       throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
    138 
    139    if (!desc)
    140       throw error(CL_INVALID_IMAGE_DESCRIPTOR);
    141 
    142    if (desc->image_array_size == 0 &&
    143        (desc->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY ||
    144         desc->image_type == CL_MEM_OBJECT_IMAGE2D_ARRAY))
    145       throw error(CL_INVALID_IMAGE_DESCRIPTOR);
    146 
    147    if (!host_ptr &&
    148        (desc->image_row_pitch || desc->image_slice_pitch))
    149       throw error(CL_INVALID_IMAGE_DESCRIPTOR);
    150 
    151    if (desc->num_mip_levels || desc->num_samples)
    152       throw error(CL_INVALID_IMAGE_DESCRIPTOR);
    153 
    154    if (bool(desc->buffer) != (desc->image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER))
    155       throw error(CL_INVALID_IMAGE_DESCRIPTOR);
    156 
    157    if (bool(host_ptr) != bool(d_flags & (CL_MEM_USE_HOST_PTR |
    158                                          CL_MEM_COPY_HOST_PTR)))
    159       throw error(CL_INVALID_HOST_PTR);
    160 
    161    const cl_mem_flags flags = validate_flags(desc->buffer, d_flags);
    162 
    163    if (!supported_formats(ctx, desc->image_type).count(*format))
    164       throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
    165 
    166    ret_error(r_errcode, CL_SUCCESS);
    167 
    168    switch (desc->image_type) {
    169    case CL_MEM_OBJECT_IMAGE2D:
    170       if (!desc->image_width || !desc->image_height)
    171          throw error(CL_INVALID_IMAGE_SIZE);
    172 
    173       if (all_of([=](const device &dev) {
    174                const size_t max = 1 << dev.max_image_levels_2d();
    175                return (desc->image_width > max ||
    176                        desc->image_height > max);
    177             }, ctx.devices()))
    178          throw error(CL_INVALID_IMAGE_SIZE);
    179 
    180       return new image2d(ctx, flags, format,
    181                          desc->image_width, desc->image_height,
    182                          desc->image_row_pitch, host_ptr);
    183 
    184    case CL_MEM_OBJECT_IMAGE3D:
    185       if (!desc->image_width || !desc->image_height || !desc->image_depth)
    186          throw error(CL_INVALID_IMAGE_SIZE);
    187 
    188       if (all_of([=](const device &dev) {
    189                const size_t max = 1 << dev.max_image_levels_3d();
    190                return (desc->image_width > max ||
    191                        desc->image_height > max ||
    192                        desc->image_depth > max);
    193             }, ctx.devices()))
    194          throw error(CL_INVALID_IMAGE_SIZE);
    195 
    196       return new image3d(ctx, flags, format,
    197                          desc->image_width, desc->image_height,
    198                          desc->image_depth, desc->image_row_pitch,
    199                          desc->image_slice_pitch, host_ptr);
    200 
    201    case CL_MEM_OBJECT_IMAGE1D:
    202    case CL_MEM_OBJECT_IMAGE1D_ARRAY:
    203    case CL_MEM_OBJECT_IMAGE1D_BUFFER:
    204    case CL_MEM_OBJECT_IMAGE2D_ARRAY:
    205       // XXX - Not implemented.
    206       throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
    207 
    208    default:
    209       throw error(CL_INVALID_IMAGE_DESCRIPTOR);
    210    }
    211 
    212 } catch (error &e) {
    213    ret_error(r_errcode, e);
    214    return NULL;
    215 }
    216 
    217 CLOVER_API cl_mem
    218 clCreateImage2D(cl_context d_ctx, cl_mem_flags d_flags,
    219                 const cl_image_format *format,
    220                 size_t width, size_t height, size_t row_pitch,
    221                 void *host_ptr, cl_int *r_errcode) {
    222    const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE2D, width, height, 0, 0,
    223                                 row_pitch, 0, 0, 0, NULL };
    224 
    225    return clCreateImage(d_ctx, d_flags, format, &desc, host_ptr, r_errcode);
    226 }
    227 
    228 CLOVER_API cl_mem
    229 clCreateImage3D(cl_context d_ctx, cl_mem_flags d_flags,
    230                 const cl_image_format *format,
    231                 size_t width, size_t height, size_t depth,
    232                 size_t row_pitch, size_t slice_pitch,
    233                 void *host_ptr, cl_int *r_errcode) {
    234    const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE3D, width, height, depth, 0,
    235                                 row_pitch, slice_pitch, 0, 0, NULL };
    236 
    237    return clCreateImage(d_ctx, d_flags, format, &desc, host_ptr, r_errcode);
    238 }
    239 
    240 CLOVER_API cl_int
    241 clGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags,
    242                            cl_mem_object_type type, cl_uint count,
    243                            cl_image_format *r_buf, cl_uint *r_count) try {
    244    auto &ctx = obj(d_ctx);
    245    auto formats = supported_formats(ctx, type);
    246 
    247    validate_flags(NULL, flags);
    248 
    249    if (r_buf && !r_count)
    250       throw error(CL_INVALID_VALUE);
    251 
    252    if (r_buf)
    253       std::copy_n(formats.begin(),
    254                   std::min((cl_uint)formats.size(), count),
    255                   r_buf);
    256 
    257    if (r_count)
    258       *r_count = formats.size();
    259 
    260    return CL_SUCCESS;
    261 
    262 } catch (error &e) {
    263    return e.get();
    264 }
    265 
    266 CLOVER_API cl_int
    267 clGetMemObjectInfo(cl_mem d_mem, cl_mem_info param,
    268                    size_t size, void *r_buf, size_t *r_size) try {
    269    property_buffer buf { r_buf, size, r_size };
    270    auto &mem = obj(d_mem);
    271 
    272    switch (param) {
    273    case CL_MEM_TYPE:
    274       buf.as_scalar<cl_mem_object_type>() = mem.type();
    275       break;
    276 
    277    case CL_MEM_FLAGS:
    278       buf.as_scalar<cl_mem_flags>() = mem.flags();
    279       break;
    280 
    281    case CL_MEM_SIZE:
    282       buf.as_scalar<size_t>() = mem.size();
    283       break;
    284 
    285    case CL_MEM_HOST_PTR:
    286       buf.as_scalar<void *>() = mem.host_ptr();
    287       break;
    288 
    289    case CL_MEM_MAP_COUNT:
    290       buf.as_scalar<cl_uint>() = 0;
    291       break;
    292 
    293    case CL_MEM_REFERENCE_COUNT:
    294       buf.as_scalar<cl_uint>() = mem.ref_count();
    295       break;
    296 
    297    case CL_MEM_CONTEXT:
    298       buf.as_scalar<cl_context>() = desc(mem.context());
    299       break;
    300 
    301    case CL_MEM_ASSOCIATED_MEMOBJECT: {
    302       sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
    303       buf.as_scalar<cl_mem>() = (sub ? desc(sub->parent()) : NULL);
    304       break;
    305    }
    306    case CL_MEM_OFFSET: {
    307       sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
    308       buf.as_scalar<size_t>() = (sub ? sub->offset() : 0);
    309       break;
    310    }
    311    default:
    312       throw error(CL_INVALID_VALUE);
    313    }
    314 
    315    return CL_SUCCESS;
    316 
    317 } catch (error &e) {
    318    return e.get();
    319 }
    320 
    321 CLOVER_API cl_int
    322 clGetImageInfo(cl_mem d_mem, cl_image_info param,
    323                size_t size, void *r_buf, size_t *r_size) try {
    324    property_buffer buf { r_buf, size, r_size };
    325    auto &img = obj<image>(d_mem);
    326 
    327    switch (param) {
    328    case CL_IMAGE_FORMAT:
    329       buf.as_scalar<cl_image_format>() = img.format();
    330       break;
    331 
    332    case CL_IMAGE_ELEMENT_SIZE:
    333       buf.as_scalar<size_t>() = 0;
    334       break;
    335 
    336    case CL_IMAGE_ROW_PITCH:
    337       buf.as_scalar<size_t>() = img.row_pitch();
    338       break;
    339 
    340    case CL_IMAGE_SLICE_PITCH:
    341       buf.as_scalar<size_t>() = img.slice_pitch();
    342       break;
    343 
    344    case CL_IMAGE_WIDTH:
    345       buf.as_scalar<size_t>() = img.width();
    346       break;
    347 
    348    case CL_IMAGE_HEIGHT:
    349       buf.as_scalar<size_t>() = img.height();
    350       break;
    351 
    352    case CL_IMAGE_DEPTH:
    353       buf.as_scalar<size_t>() = img.depth();
    354       break;
    355 
    356    default:
    357       throw error(CL_INVALID_VALUE);
    358    }
    359 
    360    return CL_SUCCESS;
    361 
    362 } catch (error &e) {
    363    return e.get();
    364 }
    365 
    366 CLOVER_API cl_int
    367 clRetainMemObject(cl_mem d_mem) try {
    368    obj(d_mem).retain();
    369    return CL_SUCCESS;
    370 
    371 } catch (error &e) {
    372    return e.get();
    373 }
    374 
    375 CLOVER_API cl_int
    376 clReleaseMemObject(cl_mem d_mem) try {
    377    if (obj(d_mem).release())
    378       delete pobj(d_mem);
    379 
    380    return CL_SUCCESS;
    381 
    382 } catch (error &e) {
    383    return e.get();
    384 }
    385 
    386 CLOVER_API cl_int
    387 clSetMemObjectDestructorCallback(cl_mem d_mem,
    388                                  void (CL_CALLBACK *pfn_notify)(cl_mem, void *),
    389                                  void *user_data) try {
    390    auto &mem = obj(d_mem);
    391 
    392    if (!pfn_notify)
    393       return CL_INVALID_VALUE;
    394 
    395    mem.destroy_notify([=]{ pfn_notify(d_mem, user_data); });
    396 
    397    return CL_SUCCESS;
    398 
    399 } catch (error &e) {
    400    return e.get();
    401 }
    402 
    403 CLOVER_API cl_int
    404 clEnqueueFillBuffer(cl_command_queue command_queue, cl_mem buffer,
    405                     const void *pattern, size_t pattern_size,
    406                     size_t offset, size_t size,
    407                     cl_uint num_events_in_wait_list,
    408                     const cl_event *event_wait_list,
    409                     cl_event *event) {
    410    CLOVER_NOT_SUPPORTED_UNTIL("1.2");
    411    return CL_INVALID_VALUE;
    412 }
    413 
    414 CLOVER_API cl_int
    415 clEnqueueFillImage(cl_command_queue command_queue, cl_mem image,
    416                    const void *fill_color,
    417                    const size_t *origin, const size_t *region,
    418                    cl_uint num_events_in_wait_list,
    419                    const cl_event *event_wait_list,
    420                    cl_event *event) {
    421    CLOVER_NOT_SUPPORTED_UNTIL("1.2");
    422    return CL_INVALID_VALUE;
    423 }
    424