clover: Factor out memory object flags validation to a helper function.
[mesa.git] / src / gallium / state_trackers / clover / api / memory.cpp
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 const cl_mem_flags dev_access_flags =
32 CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY;
33 const cl_mem_flags host_ptr_flags =
34 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR;
35 const cl_mem_flags all_mem_flags =
36 dev_access_flags | host_ptr_flags;
37
38 void
39 validate_flags(cl_mem_flags flags, cl_mem_flags valid) {
40 if ((flags & ~valid) ||
41 util_bitcount(flags & dev_access_flags) > 1)
42 throw error(CL_INVALID_VALUE);
43
44 if ((flags & CL_MEM_USE_HOST_PTR) &&
45 (flags & (CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR)))
46 throw error(CL_INVALID_VALUE);
47 }
48 }
49
50 CLOVER_API cl_mem
51 clCreateBuffer(cl_context d_ctx, cl_mem_flags flags, size_t size,
52 void *host_ptr, cl_int *r_errcode) try {
53 auto &ctx = obj(d_ctx);
54
55 validate_flags(flags, all_mem_flags);
56
57 if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
58 CL_MEM_COPY_HOST_PTR)))
59 throw error(CL_INVALID_HOST_PTR);
60
61 if (!size ||
62 size > fold(maximum(), cl_ulong(0),
63 map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())
64 ))
65 throw error(CL_INVALID_BUFFER_SIZE);
66
67 ret_error(r_errcode, CL_SUCCESS);
68 return new root_buffer(ctx, flags, size, host_ptr);
69
70 } catch (error &e) {
71 ret_error(r_errcode, e);
72 return NULL;
73 }
74
75 CLOVER_API cl_mem
76 clCreateSubBuffer(cl_mem d_mem, cl_mem_flags flags,
77 cl_buffer_create_type op,
78 const void *op_info, cl_int *r_errcode) try {
79 auto &parent = obj<root_buffer>(d_mem);
80
81 validate_flags(flags, dev_access_flags);
82
83 if (~flags & parent.flags() &
84 (dev_access_flags & ~CL_MEM_READ_WRITE))
85 throw error(CL_INVALID_VALUE);
86
87 if (op == CL_BUFFER_CREATE_TYPE_REGION) {
88 auto reg = reinterpret_cast<const cl_buffer_region *>(op_info);
89
90 if (!reg ||
91 reg->origin > parent.size() ||
92 reg->origin + reg->size > parent.size())
93 throw error(CL_INVALID_VALUE);
94
95 if (!reg->size)
96 throw error(CL_INVALID_BUFFER_SIZE);
97
98 ret_error(r_errcode, CL_SUCCESS);
99 return new sub_buffer(parent, flags, reg->origin, reg->size);
100
101 } else {
102 throw error(CL_INVALID_VALUE);
103 }
104
105 } catch (error &e) {
106 ret_error(r_errcode, e);
107 return NULL;
108 }
109
110 CLOVER_API cl_mem
111 clCreateImage2D(cl_context d_ctx, cl_mem_flags flags,
112 const cl_image_format *format,
113 size_t width, size_t height, size_t row_pitch,
114 void *host_ptr, cl_int *r_errcode) try {
115 auto &ctx = obj(d_ctx);
116
117 validate_flags(flags, all_mem_flags);
118
119 if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
120 throw error(CL_INVALID_OPERATION);
121
122 if (!format)
123 throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
124
125 if (width < 1 || height < 1)
126 throw error(CL_INVALID_IMAGE_SIZE);
127
128 if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
129 CL_MEM_COPY_HOST_PTR)))
130 throw error(CL_INVALID_HOST_PTR);
131
132 if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE2D).count(*format))
133 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
134
135 ret_error(r_errcode, CL_SUCCESS);
136 return new image2d(ctx, flags, format, width, height,
137 row_pitch, host_ptr);
138
139 } catch (error &e) {
140 ret_error(r_errcode, e);
141 return NULL;
142 }
143
144 CLOVER_API cl_mem
145 clCreateImage3D(cl_context d_ctx, cl_mem_flags flags,
146 const cl_image_format *format,
147 size_t width, size_t height, size_t depth,
148 size_t row_pitch, size_t slice_pitch,
149 void *host_ptr, cl_int *r_errcode) try {
150 auto &ctx = obj(d_ctx);
151
152 validate_flags(flags, all_mem_flags);
153
154 if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
155 throw error(CL_INVALID_OPERATION);
156
157 if (!format)
158 throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
159
160 if (width < 1 || height < 1 || depth < 2)
161 throw error(CL_INVALID_IMAGE_SIZE);
162
163 if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
164 CL_MEM_COPY_HOST_PTR)))
165 throw error(CL_INVALID_HOST_PTR);
166
167 if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE3D).count(*format))
168 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
169
170 ret_error(r_errcode, CL_SUCCESS);
171 return new image3d(ctx, flags, format, width, height, depth,
172 row_pitch, slice_pitch, host_ptr);
173
174 } catch (error &e) {
175 ret_error(r_errcode, e);
176 return NULL;
177 }
178
179 CLOVER_API cl_int
180 clGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags,
181 cl_mem_object_type type, cl_uint count,
182 cl_image_format *r_buf, cl_uint *r_count) try {
183 auto &ctx = obj(d_ctx);
184 auto formats = supported_formats(ctx, type);
185
186 validate_flags(flags, all_mem_flags);
187
188 if (r_buf && !r_count)
189 throw error(CL_INVALID_VALUE);
190
191 if (r_buf)
192 std::copy_n(formats.begin(),
193 std::min((cl_uint)formats.size(), count),
194 r_buf);
195
196 if (r_count)
197 *r_count = formats.size();
198
199 return CL_SUCCESS;
200
201 } catch (error &e) {
202 return e.get();
203 }
204
205 CLOVER_API cl_int
206 clGetMemObjectInfo(cl_mem d_mem, cl_mem_info param,
207 size_t size, void *r_buf, size_t *r_size) try {
208 property_buffer buf { r_buf, size, r_size };
209 auto &mem = obj(d_mem);
210
211 switch (param) {
212 case CL_MEM_TYPE:
213 buf.as_scalar<cl_mem_object_type>() = mem.type();
214 break;
215
216 case CL_MEM_FLAGS:
217 buf.as_scalar<cl_mem_flags>() = mem.flags();
218 break;
219
220 case CL_MEM_SIZE:
221 buf.as_scalar<size_t>() = mem.size();
222 break;
223
224 case CL_MEM_HOST_PTR:
225 buf.as_scalar<void *>() = mem.host_ptr();
226 break;
227
228 case CL_MEM_MAP_COUNT:
229 buf.as_scalar<cl_uint>() = 0;
230 break;
231
232 case CL_MEM_REFERENCE_COUNT:
233 buf.as_scalar<cl_uint>() = mem.ref_count();
234 break;
235
236 case CL_MEM_CONTEXT:
237 buf.as_scalar<cl_context>() = desc(mem.context());
238 break;
239
240 case CL_MEM_ASSOCIATED_MEMOBJECT: {
241 sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
242 buf.as_scalar<cl_mem>() = (sub ? desc(sub->parent()) : NULL);
243 break;
244 }
245 case CL_MEM_OFFSET: {
246 sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
247 buf.as_scalar<size_t>() = (sub ? sub->offset() : 0);
248 break;
249 }
250 default:
251 throw error(CL_INVALID_VALUE);
252 }
253
254 return CL_SUCCESS;
255
256 } catch (error &e) {
257 return e.get();
258 }
259
260 CLOVER_API cl_int
261 clGetImageInfo(cl_mem d_mem, cl_image_info param,
262 size_t size, void *r_buf, size_t *r_size) try {
263 property_buffer buf { r_buf, size, r_size };
264 auto &img = obj<image>(d_mem);
265
266 switch (param) {
267 case CL_IMAGE_FORMAT:
268 buf.as_scalar<cl_image_format>() = img.format();
269 break;
270
271 case CL_IMAGE_ELEMENT_SIZE:
272 buf.as_scalar<size_t>() = 0;
273 break;
274
275 case CL_IMAGE_ROW_PITCH:
276 buf.as_scalar<size_t>() = img.row_pitch();
277 break;
278
279 case CL_IMAGE_SLICE_PITCH:
280 buf.as_scalar<size_t>() = img.slice_pitch();
281 break;
282
283 case CL_IMAGE_WIDTH:
284 buf.as_scalar<size_t>() = img.width();
285 break;
286
287 case CL_IMAGE_HEIGHT:
288 buf.as_scalar<size_t>() = img.height();
289 break;
290
291 case CL_IMAGE_DEPTH:
292 buf.as_scalar<size_t>() = img.depth();
293 break;
294
295 default:
296 throw error(CL_INVALID_VALUE);
297 }
298
299 return CL_SUCCESS;
300
301 } catch (error &e) {
302 return e.get();
303 }
304
305 CLOVER_API cl_int
306 clRetainMemObject(cl_mem d_mem) try {
307 obj(d_mem).retain();
308 return CL_SUCCESS;
309
310 } catch (error &e) {
311 return e.get();
312 }
313
314 CLOVER_API cl_int
315 clReleaseMemObject(cl_mem d_mem) try {
316 if (obj(d_mem).release())
317 delete pobj(d_mem);
318
319 return CL_SUCCESS;
320
321 } catch (error &e) {
322 return e.get();
323 }
324
325 CLOVER_API cl_int
326 clSetMemObjectDestructorCallback(cl_mem d_mem,
327 void (CL_CALLBACK *pfn_notify)(cl_mem, void *),
328 void *user_data) try {
329 auto &mem = obj(d_mem);
330
331 if (!pfn_notify)
332 return CL_INVALID_VALUE;
333
334 mem.destroy_notify([=]{ pfn_notify(d_mem, user_data); });
335
336 return CL_SUCCESS;
337
338 } catch (error &e) {
339 return e.get();
340 }
341
342 CLOVER_API cl_mem
343 clCreateImage(cl_context d_ctx, cl_mem_flags flags,
344 const cl_image_format *format,
345 const cl_image_desc *image_desc,
346 void *host_ptr, cl_int *r_errcode) {
347 // This function was added in OpenCL 1.2
348 std::cerr << "CL user error: clCreateImage() not supported by OpenCL 1.1." <<
349 std::endl;
350 ret_error(r_errcode, CL_INVALID_OPERATION);
351 return NULL;
352 }