2 // Copyright 2012 Francisco Jerez
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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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.
23 #include "util/u_math.h"
24 #include "api/util.hpp"
25 #include "core/memory.hpp"
26 #include "core/format.hpp"
28 using namespace clover
;
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
;
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
);
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
);
54 clCreateBuffer(cl_context d_ctx
, cl_mem_flags d_flags
, size_t size
,
55 void *host_ptr
, cl_int
*r_errcode
) try {
56 const cl_mem_flags flags
= d_flags
|
57 (d_flags
& dev_access_flags
? 0 : CL_MEM_READ_WRITE
);
58 auto &ctx
= obj(d_ctx
);
60 validate_flags(d_flags
, all_mem_flags
);
62 if (bool(host_ptr
) != bool(flags
& (CL_MEM_USE_HOST_PTR
|
63 CL_MEM_COPY_HOST_PTR
)))
64 throw error(CL_INVALID_HOST_PTR
);
67 size
> fold(maximum(), cl_ulong(0),
68 map(std::mem_fn(&device::max_mem_alloc_size
), ctx
.devices())
70 throw error(CL_INVALID_BUFFER_SIZE
);
72 ret_error(r_errcode
, CL_SUCCESS
);
73 return new root_buffer(ctx
, flags
, size
, host_ptr
);
76 ret_error(r_errcode
, e
);
81 clCreateSubBuffer(cl_mem d_mem
, cl_mem_flags d_flags
,
82 cl_buffer_create_type op
,
83 const void *op_info
, cl_int
*r_errcode
) try {
84 auto &parent
= obj
<root_buffer
>(d_mem
);
85 const cl_mem_flags flags
= d_flags
|
86 (d_flags
& dev_access_flags
? 0 : parent
.flags() & dev_access_flags
) |
87 (d_flags
& host_access_flags
? 0 : parent
.flags() & host_access_flags
) |
88 (parent
.flags() & host_ptr_flags
);
90 validate_flags(d_flags
, dev_access_flags
| host_access_flags
);
92 if (~flags
& parent
.flags() &
93 ((dev_access_flags
& ~CL_MEM_READ_WRITE
) | host_access_flags
))
94 throw error(CL_INVALID_VALUE
);
96 if (op
== CL_BUFFER_CREATE_TYPE_REGION
) {
97 auto reg
= reinterpret_cast<const cl_buffer_region
*>(op_info
);
100 reg
->origin
> parent
.size() ||
101 reg
->origin
+ reg
->size
> parent
.size())
102 throw error(CL_INVALID_VALUE
);
105 throw error(CL_INVALID_BUFFER_SIZE
);
107 ret_error(r_errcode
, CL_SUCCESS
);
108 return new sub_buffer(parent
, flags
, reg
->origin
, reg
->size
);
111 throw error(CL_INVALID_VALUE
);
115 ret_error(r_errcode
, e
);
120 clCreateImage2D(cl_context d_ctx
, cl_mem_flags d_flags
,
121 const cl_image_format
*format
,
122 size_t width
, size_t height
, size_t row_pitch
,
123 void *host_ptr
, cl_int
*r_errcode
) try {
124 const cl_mem_flags flags
= d_flags
|
125 (d_flags
& dev_access_flags
? 0 : CL_MEM_READ_WRITE
);
126 auto &ctx
= obj(d_ctx
);
128 validate_flags(d_flags
, all_mem_flags
);
130 if (!any_of(std::mem_fn(&device::image_support
), ctx
.devices()))
131 throw error(CL_INVALID_OPERATION
);
134 throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR
);
136 if (width
< 1 || height
< 1)
137 throw error(CL_INVALID_IMAGE_SIZE
);
139 if (bool(host_ptr
) != bool(flags
& (CL_MEM_USE_HOST_PTR
|
140 CL_MEM_COPY_HOST_PTR
)))
141 throw error(CL_INVALID_HOST_PTR
);
143 if (!supported_formats(ctx
, CL_MEM_OBJECT_IMAGE2D
).count(*format
))
144 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED
);
146 ret_error(r_errcode
, CL_SUCCESS
);
147 return new image2d(ctx
, flags
, format
, width
, height
,
148 row_pitch
, host_ptr
);
151 ret_error(r_errcode
, e
);
156 clCreateImage3D(cl_context d_ctx
, cl_mem_flags d_flags
,
157 const cl_image_format
*format
,
158 size_t width
, size_t height
, size_t depth
,
159 size_t row_pitch
, size_t slice_pitch
,
160 void *host_ptr
, cl_int
*r_errcode
) try {
161 const cl_mem_flags flags
= d_flags
|
162 (d_flags
& dev_access_flags
? 0 : CL_MEM_READ_WRITE
);
163 auto &ctx
= obj(d_ctx
);
165 validate_flags(d_flags
, all_mem_flags
);
167 if (!any_of(std::mem_fn(&device::image_support
), ctx
.devices()))
168 throw error(CL_INVALID_OPERATION
);
171 throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR
);
173 if (width
< 1 || height
< 1 || depth
< 2)
174 throw error(CL_INVALID_IMAGE_SIZE
);
176 if (bool(host_ptr
) != bool(flags
& (CL_MEM_USE_HOST_PTR
|
177 CL_MEM_COPY_HOST_PTR
)))
178 throw error(CL_INVALID_HOST_PTR
);
180 if (!supported_formats(ctx
, CL_MEM_OBJECT_IMAGE3D
).count(*format
))
181 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED
);
183 ret_error(r_errcode
, CL_SUCCESS
);
184 return new image3d(ctx
, flags
, format
, width
, height
, depth
,
185 row_pitch
, slice_pitch
, host_ptr
);
188 ret_error(r_errcode
, e
);
193 clGetSupportedImageFormats(cl_context d_ctx
, cl_mem_flags flags
,
194 cl_mem_object_type type
, cl_uint count
,
195 cl_image_format
*r_buf
, cl_uint
*r_count
) try {
196 auto &ctx
= obj(d_ctx
);
197 auto formats
= supported_formats(ctx
, type
);
199 validate_flags(flags
, all_mem_flags
);
201 if (r_buf
&& !r_count
)
202 throw error(CL_INVALID_VALUE
);
205 std::copy_n(formats
.begin(),
206 std::min((cl_uint
)formats
.size(), count
),
210 *r_count
= formats
.size();
219 clGetMemObjectInfo(cl_mem d_mem
, cl_mem_info param
,
220 size_t size
, void *r_buf
, size_t *r_size
) try {
221 property_buffer buf
{ r_buf
, size
, r_size
};
222 auto &mem
= obj(d_mem
);
226 buf
.as_scalar
<cl_mem_object_type
>() = mem
.type();
230 buf
.as_scalar
<cl_mem_flags
>() = mem
.flags();
234 buf
.as_scalar
<size_t>() = mem
.size();
237 case CL_MEM_HOST_PTR
:
238 buf
.as_scalar
<void *>() = mem
.host_ptr();
241 case CL_MEM_MAP_COUNT
:
242 buf
.as_scalar
<cl_uint
>() = 0;
245 case CL_MEM_REFERENCE_COUNT
:
246 buf
.as_scalar
<cl_uint
>() = mem
.ref_count();
250 buf
.as_scalar
<cl_context
>() = desc(mem
.context());
253 case CL_MEM_ASSOCIATED_MEMOBJECT
: {
254 sub_buffer
*sub
= dynamic_cast<sub_buffer
*>(&mem
);
255 buf
.as_scalar
<cl_mem
>() = (sub
? desc(sub
->parent()) : NULL
);
258 case CL_MEM_OFFSET
: {
259 sub_buffer
*sub
= dynamic_cast<sub_buffer
*>(&mem
);
260 buf
.as_scalar
<size_t>() = (sub
? sub
->offset() : 0);
264 throw error(CL_INVALID_VALUE
);
274 clGetImageInfo(cl_mem d_mem
, cl_image_info param
,
275 size_t size
, void *r_buf
, size_t *r_size
) try {
276 property_buffer buf
{ r_buf
, size
, r_size
};
277 auto &img
= obj
<image
>(d_mem
);
280 case CL_IMAGE_FORMAT
:
281 buf
.as_scalar
<cl_image_format
>() = img
.format();
284 case CL_IMAGE_ELEMENT_SIZE
:
285 buf
.as_scalar
<size_t>() = 0;
288 case CL_IMAGE_ROW_PITCH
:
289 buf
.as_scalar
<size_t>() = img
.row_pitch();
292 case CL_IMAGE_SLICE_PITCH
:
293 buf
.as_scalar
<size_t>() = img
.slice_pitch();
297 buf
.as_scalar
<size_t>() = img
.width();
300 case CL_IMAGE_HEIGHT
:
301 buf
.as_scalar
<size_t>() = img
.height();
305 buf
.as_scalar
<size_t>() = img
.depth();
309 throw error(CL_INVALID_VALUE
);
319 clRetainMemObject(cl_mem d_mem
) try {
328 clReleaseMemObject(cl_mem d_mem
) try {
329 if (obj(d_mem
).release())
339 clSetMemObjectDestructorCallback(cl_mem d_mem
,
340 void (CL_CALLBACK
*pfn_notify
)(cl_mem
, void *),
341 void *user_data
) try {
342 auto &mem
= obj(d_mem
);
345 return CL_INVALID_VALUE
;
347 mem
.destroy_notify([=]{ pfn_notify(d_mem
, user_data
); });
356 clCreateImage(cl_context d_ctx
, cl_mem_flags flags
,
357 const cl_image_format
*format
,
358 const cl_image_desc
*image_desc
,
359 void *host_ptr
, cl_int
*r_errcode
) {
360 CLOVER_NOT_SUPPORTED_UNTIL("1.2");
361 ret_error(r_errcode
, CL_INVALID_OPERATION
);
366 clEnqueueFillBuffer(cl_command_queue command_queue
, cl_mem buffer
,
367 const void *pattern
, size_t pattern_size
,
368 size_t offset
, size_t size
,
369 cl_uint num_events_in_wait_list
,
370 const cl_event
*event_wait_list
,
372 CLOVER_NOT_SUPPORTED_UNTIL("1.2");
373 return CL_INVALID_VALUE
;
377 clEnqueueFillImage(cl_command_queue command_queue
, cl_mem image
,
378 const void *fill_color
,
379 const size_t *origin
, const size_t *region
,
380 cl_uint num_events_in_wait_list
,
381 const cl_event
*event_wait_list
,
383 CLOVER_NOT_SUPPORTED_UNTIL("1.2");
384 return CL_INVALID_VALUE
;