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