• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
validate_flags(cl_mem d_parent,cl_mem_flags d_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
clCreateBuffer(cl_context d_ctx,cl_mem_flags d_flags,size_t size,void * host_ptr,cl_int * r_errcode)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
clCreateSubBuffer(cl_mem d_mem,cl_mem_flags d_flags,cl_buffer_create_type op,const void * op_info,cl_int * r_errcode)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
clCreateImage(cl_context d_ctx,cl_mem_flags d_flags,const cl_image_format * format,const cl_image_desc * desc,void * host_ptr,cl_int * r_errcode)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
clCreateImage2D(cl_context d_ctx,cl_mem_flags d_flags,const cl_image_format * format,size_t width,size_t height,size_t row_pitch,void * host_ptr,cl_int * r_errcode)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
clCreateImage3D(cl_context d_ctx,cl_mem_flags d_flags,const cl_image_format * format,size_t width,size_t height,size_t depth,size_t row_pitch,size_t slice_pitch,void * host_ptr,cl_int * r_errcode)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
clGetSupportedImageFormats(cl_context d_ctx,cl_mem_flags flags,cl_mem_object_type type,cl_uint count,cl_image_format * r_buf,cl_uint * r_count)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
clGetMemObjectInfo(cl_mem d_mem,cl_mem_info param,size_t size,void * r_buf,size_t * r_size)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
clGetImageInfo(cl_mem d_mem,cl_image_info param,size_t size,void * r_buf,size_t * r_size)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
clRetainMemObject(cl_mem d_mem)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
clReleaseMemObject(cl_mem d_mem)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
clSetMemObjectDestructorCallback(cl_mem d_mem,void (CL_CALLBACK * pfn_notify)(cl_mem,void *),void * user_data)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
clEnqueueFillBuffer(cl_command_queue command_queue,cl_mem buffer,const void * pattern,size_t pattern_size,size_t offset,size_t size,cl_uint num_events_in_wait_list,const cl_event * event_wait_list,cl_event * event)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
clEnqueueFillImage(cl_command_queue command_queue,cl_mem image,const void * fill_color,const size_t * origin,const size_t * region,cl_uint num_events_in_wait_list,const cl_event * event_wait_list,cl_event * event)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