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/memory.hpp"
25 #include "core/format.hpp"
26
27 using namespace clover;
28
29 PUBLIC cl_mem
clCreateBuffer(cl_context ctx,cl_mem_flags flags,size_t size,void * host_ptr,cl_int * errcode_ret)30 clCreateBuffer(cl_context ctx, cl_mem_flags flags, size_t size,
31 void *host_ptr, cl_int *errcode_ret) try {
32 if (!ctx)
33 throw error(CL_INVALID_CONTEXT);
34
35 if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
36 CL_MEM_COPY_HOST_PTR)))
37 throw error(CL_INVALID_HOST_PTR);
38
39 if (!size)
40 throw error(CL_INVALID_BUFFER_SIZE);
41
42 if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
43 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
44 CL_MEM_COPY_HOST_PTR))
45 throw error(CL_INVALID_VALUE);
46
47 ret_error(errcode_ret, CL_SUCCESS);
48 return new root_buffer(*ctx, flags, size, host_ptr);
49
50 } catch (error &e) {
51 ret_error(errcode_ret, e);
52 return NULL;
53 }
54
55 PUBLIC cl_mem
clCreateSubBuffer(cl_mem obj,cl_mem_flags flags,cl_buffer_create_type op,const void * op_info,cl_int * errcode_ret)56 clCreateSubBuffer(cl_mem obj, cl_mem_flags flags, cl_buffer_create_type op,
57 const void *op_info, cl_int *errcode_ret) try {
58 root_buffer *parent = dynamic_cast<root_buffer *>(obj);
59
60 if (!parent)
61 throw error(CL_INVALID_MEM_OBJECT);
62
63 if ((flags & (CL_MEM_USE_HOST_PTR |
64 CL_MEM_ALLOC_HOST_PTR |
65 CL_MEM_COPY_HOST_PTR)) ||
66 (~flags & parent->flags() & (CL_MEM_READ_ONLY |
67 CL_MEM_WRITE_ONLY)))
68 throw error(CL_INVALID_VALUE);
69
70 if (op == CL_BUFFER_CREATE_TYPE_REGION) {
71 const cl_buffer_region *reg = (const cl_buffer_region *)op_info;
72
73 if (!reg ||
74 reg->origin > parent->size() ||
75 reg->origin + reg->size > parent->size())
76 throw error(CL_INVALID_VALUE);
77
78 if (!reg->size)
79 throw error(CL_INVALID_BUFFER_SIZE);
80
81 ret_error(errcode_ret, CL_SUCCESS);
82 return new sub_buffer(*parent, flags, reg->origin, reg->size);
83
84 } else {
85 throw error(CL_INVALID_VALUE);
86 }
87
88 } catch (error &e) {
89 ret_error(errcode_ret, e);
90 return NULL;
91 }
92
93 PUBLIC cl_mem
clCreateImage2D(cl_context ctx,cl_mem_flags flags,const cl_image_format * format,size_t width,size_t height,size_t row_pitch,void * host_ptr,cl_int * errcode_ret)94 clCreateImage2D(cl_context ctx, cl_mem_flags flags,
95 const cl_image_format *format,
96 size_t width, size_t height, size_t row_pitch,
97 void *host_ptr, cl_int *errcode_ret) try {
98 if (!ctx)
99 throw error(CL_INVALID_CONTEXT);
100
101 if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
102 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
103 CL_MEM_COPY_HOST_PTR))
104 throw error(CL_INVALID_VALUE);
105
106 if (!format)
107 throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
108
109 if (width < 1 || height < 1)
110 throw error(CL_INVALID_IMAGE_SIZE);
111
112 if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
113 CL_MEM_COPY_HOST_PTR)))
114 throw error(CL_INVALID_HOST_PTR);
115
116 if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE2D).count(*format))
117 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
118
119 ret_error(errcode_ret, CL_SUCCESS);
120 return new image2d(*ctx, flags, format, width, height,
121 row_pitch, host_ptr);
122
123 } catch (error &e) {
124 ret_error(errcode_ret, e);
125 return NULL;
126 }
127
128 PUBLIC cl_mem
clCreateImage3D(cl_context ctx,cl_mem_flags 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 * errcode_ret)129 clCreateImage3D(cl_context ctx, cl_mem_flags flags,
130 const cl_image_format *format,
131 size_t width, size_t height, size_t depth,
132 size_t row_pitch, size_t slice_pitch,
133 void *host_ptr, cl_int *errcode_ret) try {
134 if (!ctx)
135 throw error(CL_INVALID_CONTEXT);
136
137 if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
138 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
139 CL_MEM_COPY_HOST_PTR))
140 throw error(CL_INVALID_VALUE);
141
142 if (!format)
143 throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
144
145 if (width < 1 || height < 1 || depth < 2)
146 throw error(CL_INVALID_IMAGE_SIZE);
147
148 if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
149 CL_MEM_COPY_HOST_PTR)))
150 throw error(CL_INVALID_HOST_PTR);
151
152 if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE3D).count(*format))
153 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
154
155 ret_error(errcode_ret, CL_SUCCESS);
156 return new image3d(*ctx, flags, format, width, height, depth,
157 row_pitch, slice_pitch, host_ptr);
158
159 } catch (error &e) {
160 ret_error(errcode_ret, e);
161 return NULL;
162 }
163
164 PUBLIC cl_int
clGetSupportedImageFormats(cl_context ctx,cl_mem_flags flags,cl_mem_object_type type,cl_uint count,cl_image_format * buf,cl_uint * count_ret)165 clGetSupportedImageFormats(cl_context ctx, cl_mem_flags flags,
166 cl_mem_object_type type, cl_uint count,
167 cl_image_format *buf, cl_uint *count_ret) try {
168 if (!ctx)
169 throw error(CL_INVALID_CONTEXT);
170
171 if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
172 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
173 CL_MEM_COPY_HOST_PTR))
174 throw error(CL_INVALID_VALUE);
175
176 if (!count && buf)
177 throw error(CL_INVALID_VALUE);
178
179 auto formats = supported_formats(ctx, type);
180
181 if (buf)
182 std::copy_n(formats.begin(), std::min((cl_uint)formats.size(), count),
183 buf);
184 if (count_ret)
185 *count_ret = formats.size();
186
187 return CL_SUCCESS;
188
189 } catch (error &e) {
190 return e.get();
191 }
192
193 PUBLIC cl_int
clGetMemObjectInfo(cl_mem obj,cl_mem_info param,size_t size,void * buf,size_t * size_ret)194 clGetMemObjectInfo(cl_mem obj, cl_mem_info param,
195 size_t size, void *buf, size_t *size_ret) {
196 if (!obj)
197 return CL_INVALID_MEM_OBJECT;
198
199 switch (param) {
200 case CL_MEM_TYPE:
201 return scalar_property<cl_mem_object_type>(buf, size, size_ret,
202 obj->type());
203
204 case CL_MEM_FLAGS:
205 return scalar_property<cl_mem_flags>(buf, size, size_ret, obj->flags());
206
207 case CL_MEM_SIZE:
208 return scalar_property<size_t>(buf, size, size_ret, obj->size());
209
210 case CL_MEM_HOST_PTR:
211 return scalar_property<void *>(buf, size, size_ret, obj->host_ptr());
212
213 case CL_MEM_MAP_COUNT:
214 return scalar_property<cl_uint>(buf, size, size_ret, 0);
215
216 case CL_MEM_REFERENCE_COUNT:
217 return scalar_property<cl_uint>(buf, size, size_ret, obj->ref_count());
218
219 case CL_MEM_CONTEXT:
220 return scalar_property<cl_context>(buf, size, size_ret, &obj->ctx);
221
222 case CL_MEM_ASSOCIATED_MEMOBJECT: {
223 sub_buffer *sub = dynamic_cast<sub_buffer *>(obj);
224 return scalar_property<cl_mem>(buf, size, size_ret,
225 (sub ? &sub->parent : NULL));
226 }
227 case CL_MEM_OFFSET: {
228 sub_buffer *sub = dynamic_cast<sub_buffer *>(obj);
229 return scalar_property<size_t>(buf, size, size_ret,
230 (sub ? sub->offset() : 0));
231 }
232 default:
233 return CL_INVALID_VALUE;
234 }
235 }
236
237 PUBLIC cl_int
clGetImageInfo(cl_mem obj,cl_image_info param,size_t size,void * buf,size_t * size_ret)238 clGetImageInfo(cl_mem obj, cl_image_info param,
239 size_t size, void *buf, size_t *size_ret) {
240 image *img = dynamic_cast<image *>(obj);
241 if (!img)
242 return CL_INVALID_MEM_OBJECT;
243
244 switch (param) {
245 case CL_IMAGE_FORMAT:
246 return scalar_property<cl_image_format>(buf, size, size_ret,
247 img->format());
248
249 case CL_IMAGE_ELEMENT_SIZE:
250 return scalar_property<size_t>(buf, size, size_ret, 0);
251
252 case CL_IMAGE_ROW_PITCH:
253 return scalar_property<size_t>(buf, size, size_ret, img->row_pitch());
254
255 case CL_IMAGE_SLICE_PITCH:
256 return scalar_property<size_t>(buf, size, size_ret, img->slice_pitch());
257
258 case CL_IMAGE_WIDTH:
259 return scalar_property<size_t>(buf, size, size_ret, img->width());
260
261 case CL_IMAGE_HEIGHT:
262 return scalar_property<size_t>(buf, size, size_ret, img->height());
263
264 case CL_IMAGE_DEPTH:
265 return scalar_property<size_t>(buf, size, size_ret, img->depth());
266
267 default:
268 return CL_INVALID_VALUE;
269 }
270 }
271
272 PUBLIC cl_int
clRetainMemObject(cl_mem obj)273 clRetainMemObject(cl_mem obj) {
274 if (!obj)
275 return CL_INVALID_MEM_OBJECT;
276
277 obj->retain();
278 return CL_SUCCESS;
279 }
280
281 PUBLIC cl_int
clReleaseMemObject(cl_mem obj)282 clReleaseMemObject(cl_mem obj) {
283 if (!obj)
284 return CL_INVALID_MEM_OBJECT;
285
286 if (obj->release())
287 delete obj;
288
289 return CL_SUCCESS;
290 }
291
292 PUBLIC cl_int
clSetMemObjectDestructorCallback(cl_mem obj,void (CL_CALLBACK * pfn_notify)(cl_mem,void *),void * user_data)293 clSetMemObjectDestructorCallback(cl_mem obj,
294 void (CL_CALLBACK *pfn_notify)(cl_mem, void *),
295 void *user_data) {
296 if (!obj)
297 return CL_INVALID_MEM_OBJECT;
298
299 if (!pfn_notify)
300 return CL_INVALID_VALUE;
301
302 obj->destroy_notify([=]{ pfn_notify(obj, user_data); });
303
304 return CL_SUCCESS;
305 }
306