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