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