memory.cpp revision c6db1b3396384186aab5b685fe1fd540e17b3a62
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
27using namespace clover;
28
29PUBLIC cl_mem
30clCreateBuffer(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_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
55PUBLIC cl_mem
56clCreateSubBuffer(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
93PUBLIC cl_mem
94clCreateImage2D(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_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
128PUBLIC cl_mem
129clCreateImage3D(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_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
164PUBLIC cl_int
165clGetSupportedImageFormats(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_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
193PUBLIC cl_int
194clGetMemObjectInfo(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
237PUBLIC cl_int
238clGetImageInfo(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
272PUBLIC cl_int
273clRetainMemObject(cl_mem obj) {
274   if (!obj)
275      return CL_INVALID_MEM_OBJECT;
276
277   obj->retain();
278   return CL_SUCCESS;
279}
280
281PUBLIC cl_int
282clReleaseMemObject(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
292PUBLIC cl_int
293clSetMemObjectDestructorCallback(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