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 cl_mem_flags 32 validate_flags(cl_mem d_parent, cl_mem_flags d_flags) { 33 const cl_mem_flags dev_access_flags = 34 CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY; 35 const cl_mem_flags host_ptr_flags = 36 CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR; 37 const cl_mem_flags host_access_flags = 38 CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS; 39 const cl_mem_flags valid_flags = 40 dev_access_flags | host_access_flags | (d_parent ? 0 : host_ptr_flags); 41 42 if ((d_flags & ~valid_flags) || 43 util_bitcount(d_flags & dev_access_flags) > 1 || 44 util_bitcount(d_flags & host_access_flags) > 1) 45 throw error(CL_INVALID_VALUE); 46 47 if ((d_flags & CL_MEM_USE_HOST_PTR) && 48 (d_flags & (CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR))) 49 throw error(CL_INVALID_VALUE); 50 51 if (d_parent) { 52 const auto &parent = obj(d_parent); 53 const cl_mem_flags flags = (d_flags | 54 (d_flags & dev_access_flags ? 0 : 55 parent.flags() & dev_access_flags) | 56 (d_flags & host_access_flags ? 0 : 57 parent.flags() & host_access_flags) | 58 (parent.flags() & host_ptr_flags)); 59 60 if (~flags & parent.flags() & 61 ((dev_access_flags & ~CL_MEM_READ_WRITE) | host_access_flags)) 62 throw error(CL_INVALID_VALUE); 63 64 return flags; 65 66 } else { 67 return d_flags | (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE); 68 } 69 } 70 } 71 72 CLOVER_API cl_mem 73 clCreateBuffer(cl_context d_ctx, cl_mem_flags d_flags, size_t size, 74 void *host_ptr, cl_int *r_errcode) try { 75 const cl_mem_flags flags = validate_flags(NULL, d_flags); 76 auto &ctx = obj(d_ctx); 77 78 if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR | 79 CL_MEM_COPY_HOST_PTR))) 80 throw error(CL_INVALID_HOST_PTR); 81 82 if (!size || 83 size > fold(maximum(), cl_ulong(0), 84 map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices()) 85 )) 86 throw error(CL_INVALID_BUFFER_SIZE); 87 88 ret_error(r_errcode, CL_SUCCESS); 89 return new root_buffer(ctx, flags, size, host_ptr); 90 91 } catch (error &e) { 92 ret_error(r_errcode, e); 93 return NULL; 94 } 95 96 CLOVER_API cl_mem 97 clCreateSubBuffer(cl_mem d_mem, cl_mem_flags d_flags, 98 cl_buffer_create_type op, 99 const void *op_info, cl_int *r_errcode) try { 100 auto &parent = obj<root_buffer>(d_mem); 101 const cl_mem_flags flags = validate_flags(d_mem, d_flags); 102 103 if (op == CL_BUFFER_CREATE_TYPE_REGION) { 104 auto reg = reinterpret_cast<const cl_buffer_region *>(op_info); 105 106 if (!reg || 107 reg->origin > parent.size() || 108 reg->origin + reg->size > parent.size()) 109 throw error(CL_INVALID_VALUE); 110 111 if (!reg->size) 112 throw error(CL_INVALID_BUFFER_SIZE); 113 114 ret_error(r_errcode, CL_SUCCESS); 115 return new sub_buffer(parent, flags, reg->origin, reg->size); 116 117 } else { 118 throw error(CL_INVALID_VALUE); 119 } 120 121 } catch (error &e) { 122 ret_error(r_errcode, e); 123 return NULL; 124 } 125 126 CLOVER_API cl_mem 127 clCreateImage(cl_context d_ctx, cl_mem_flags d_flags, 128 const cl_image_format *format, 129 const cl_image_desc *desc, 130 void *host_ptr, cl_int *r_errcode) try { 131 auto &ctx = obj(d_ctx); 132 133 if (!any_of(std::mem_fn(&device::image_support), ctx.devices())) 134 throw error(CL_INVALID_OPERATION); 135 136 if (!format) 137 throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR); 138 139 if (!desc) 140 throw error(CL_INVALID_IMAGE_DESCRIPTOR); 141 142 if (desc->image_array_size == 0 && 143 (desc->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY || 144 desc->image_type == CL_MEM_OBJECT_IMAGE2D_ARRAY)) 145 throw error(CL_INVALID_IMAGE_DESCRIPTOR); 146 147 if (!host_ptr && 148 (desc->image_row_pitch || desc->image_slice_pitch)) 149 throw error(CL_INVALID_IMAGE_DESCRIPTOR); 150 151 if (desc->num_mip_levels || desc->num_samples) 152 throw error(CL_INVALID_IMAGE_DESCRIPTOR); 153 154 if (bool(desc->buffer) != (desc->image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER)) 155 throw error(CL_INVALID_IMAGE_DESCRIPTOR); 156 157 if (bool(host_ptr) != bool(d_flags & (CL_MEM_USE_HOST_PTR | 158 CL_MEM_COPY_HOST_PTR))) 159 throw error(CL_INVALID_HOST_PTR); 160 161 const cl_mem_flags flags = validate_flags(desc->buffer, d_flags); 162 163 if (!supported_formats(ctx, desc->image_type).count(*format)) 164 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED); 165 166 ret_error(r_errcode, CL_SUCCESS); 167 168 switch (desc->image_type) { 169 case CL_MEM_OBJECT_IMAGE2D: 170 if (!desc->image_width || !desc->image_height) 171 throw error(CL_INVALID_IMAGE_SIZE); 172 173 if (all_of([=](const device &dev) { 174 const size_t max = 1 << dev.max_image_levels_2d(); 175 return (desc->image_width > max || 176 desc->image_height > max); 177 }, ctx.devices())) 178 throw error(CL_INVALID_IMAGE_SIZE); 179 180 return new image2d(ctx, flags, format, 181 desc->image_width, desc->image_height, 182 desc->image_row_pitch, host_ptr); 183 184 case CL_MEM_OBJECT_IMAGE3D: 185 if (!desc->image_width || !desc->image_height || !desc->image_depth) 186 throw error(CL_INVALID_IMAGE_SIZE); 187 188 if (all_of([=](const device &dev) { 189 const size_t max = 1 << dev.max_image_levels_3d(); 190 return (desc->image_width > max || 191 desc->image_height > max || 192 desc->image_depth > max); 193 }, ctx.devices())) 194 throw error(CL_INVALID_IMAGE_SIZE); 195 196 return new image3d(ctx, flags, format, 197 desc->image_width, desc->image_height, 198 desc->image_depth, desc->image_row_pitch, 199 desc->image_slice_pitch, host_ptr); 200 201 case CL_MEM_OBJECT_IMAGE1D: 202 case CL_MEM_OBJECT_IMAGE1D_ARRAY: 203 case CL_MEM_OBJECT_IMAGE1D_BUFFER: 204 case CL_MEM_OBJECT_IMAGE2D_ARRAY: 205 // XXX - Not implemented. 206 throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED); 207 208 default: 209 throw error(CL_INVALID_IMAGE_DESCRIPTOR); 210 } 211 212 } catch (error &e) { 213 ret_error(r_errcode, e); 214 return NULL; 215 } 216 217 CLOVER_API cl_mem 218 clCreateImage2D(cl_context d_ctx, cl_mem_flags d_flags, 219 const cl_image_format *format, 220 size_t width, size_t height, size_t row_pitch, 221 void *host_ptr, cl_int *r_errcode) { 222 const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE2D, width, height, 0, 0, 223 row_pitch, 0, 0, 0, NULL }; 224 225 return clCreateImage(d_ctx, d_flags, format, &desc, host_ptr, r_errcode); 226 } 227 228 CLOVER_API cl_mem 229 clCreateImage3D(cl_context d_ctx, cl_mem_flags d_flags, 230 const cl_image_format *format, 231 size_t width, size_t height, size_t depth, 232 size_t row_pitch, size_t slice_pitch, 233 void *host_ptr, cl_int *r_errcode) { 234 const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE3D, width, height, depth, 0, 235 row_pitch, slice_pitch, 0, 0, NULL }; 236 237 return clCreateImage(d_ctx, d_flags, format, &desc, host_ptr, r_errcode); 238 } 239 240 CLOVER_API cl_int 241 clGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags, 242 cl_mem_object_type type, cl_uint count, 243 cl_image_format *r_buf, cl_uint *r_count) try { 244 auto &ctx = obj(d_ctx); 245 auto formats = supported_formats(ctx, type); 246 247 validate_flags(NULL, flags); 248 249 if (r_buf && !r_count) 250 throw error(CL_INVALID_VALUE); 251 252 if (r_buf) 253 std::copy_n(formats.begin(), 254 std::min((cl_uint)formats.size(), count), 255 r_buf); 256 257 if (r_count) 258 *r_count = formats.size(); 259 260 return CL_SUCCESS; 261 262 } catch (error &e) { 263 return e.get(); 264 } 265 266 CLOVER_API cl_int 267 clGetMemObjectInfo(cl_mem d_mem, cl_mem_info param, 268 size_t size, void *r_buf, size_t *r_size) try { 269 property_buffer buf { r_buf, size, r_size }; 270 auto &mem = obj(d_mem); 271 272 switch (param) { 273 case CL_MEM_TYPE: 274 buf.as_scalar<cl_mem_object_type>() = mem.type(); 275 break; 276 277 case CL_MEM_FLAGS: 278 buf.as_scalar<cl_mem_flags>() = mem.flags(); 279 break; 280 281 case CL_MEM_SIZE: 282 buf.as_scalar<size_t>() = mem.size(); 283 break; 284 285 case CL_MEM_HOST_PTR: 286 buf.as_scalar<void *>() = mem.host_ptr(); 287 break; 288 289 case CL_MEM_MAP_COUNT: 290 buf.as_scalar<cl_uint>() = 0; 291 break; 292 293 case CL_MEM_REFERENCE_COUNT: 294 buf.as_scalar<cl_uint>() = mem.ref_count(); 295 break; 296 297 case CL_MEM_CONTEXT: 298 buf.as_scalar<cl_context>() = desc(mem.context()); 299 break; 300 301 case CL_MEM_ASSOCIATED_MEMOBJECT: { 302 sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem); 303 buf.as_scalar<cl_mem>() = (sub ? desc(sub->parent()) : NULL); 304 break; 305 } 306 case CL_MEM_OFFSET: { 307 sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem); 308 buf.as_scalar<size_t>() = (sub ? sub->offset() : 0); 309 break; 310 } 311 default: 312 throw error(CL_INVALID_VALUE); 313 } 314 315 return CL_SUCCESS; 316 317 } catch (error &e) { 318 return e.get(); 319 } 320 321 CLOVER_API cl_int 322 clGetImageInfo(cl_mem d_mem, cl_image_info param, 323 size_t size, void *r_buf, size_t *r_size) try { 324 property_buffer buf { r_buf, size, r_size }; 325 auto &img = obj<image>(d_mem); 326 327 switch (param) { 328 case CL_IMAGE_FORMAT: 329 buf.as_scalar<cl_image_format>() = img.format(); 330 break; 331 332 case CL_IMAGE_ELEMENT_SIZE: 333 buf.as_scalar<size_t>() = 0; 334 break; 335 336 case CL_IMAGE_ROW_PITCH: 337 buf.as_scalar<size_t>() = img.row_pitch(); 338 break; 339 340 case CL_IMAGE_SLICE_PITCH: 341 buf.as_scalar<size_t>() = img.slice_pitch(); 342 break; 343 344 case CL_IMAGE_WIDTH: 345 buf.as_scalar<size_t>() = img.width(); 346 break; 347 348 case CL_IMAGE_HEIGHT: 349 buf.as_scalar<size_t>() = img.height(); 350 break; 351 352 case CL_IMAGE_DEPTH: 353 buf.as_scalar<size_t>() = img.depth(); 354 break; 355 356 default: 357 throw error(CL_INVALID_VALUE); 358 } 359 360 return CL_SUCCESS; 361 362 } catch (error &e) { 363 return e.get(); 364 } 365 366 CLOVER_API cl_int 367 clRetainMemObject(cl_mem d_mem) try { 368 obj(d_mem).retain(); 369 return CL_SUCCESS; 370 371 } catch (error &e) { 372 return e.get(); 373 } 374 375 CLOVER_API cl_int 376 clReleaseMemObject(cl_mem d_mem) try { 377 if (obj(d_mem).release()) 378 delete pobj(d_mem); 379 380 return CL_SUCCESS; 381 382 } catch (error &e) { 383 return e.get(); 384 } 385 386 CLOVER_API cl_int 387 clSetMemObjectDestructorCallback(cl_mem d_mem, 388 void (CL_CALLBACK *pfn_notify)(cl_mem, void *), 389 void *user_data) try { 390 auto &mem = obj(d_mem); 391 392 if (!pfn_notify) 393 return CL_INVALID_VALUE; 394 395 mem.destroy_notify([=]{ pfn_notify(d_mem, user_data); }); 396 397 return CL_SUCCESS; 398 399 } catch (error &e) { 400 return e.get(); 401 } 402 403 CLOVER_API cl_int 404 clEnqueueFillBuffer(cl_command_queue command_queue, cl_mem buffer, 405 const void *pattern, size_t pattern_size, 406 size_t offset, size_t size, 407 cl_uint num_events_in_wait_list, 408 const cl_event *event_wait_list, 409 cl_event *event) { 410 CLOVER_NOT_SUPPORTED_UNTIL("1.2"); 411 return CL_INVALID_VALUE; 412 } 413 414 CLOVER_API cl_int 415 clEnqueueFillImage(cl_command_queue command_queue, cl_mem image, 416 const void *fill_color, 417 const size_t *origin, const size_t *region, 418 cl_uint num_events_in_wait_list, 419 const cl_event *event_wait_list, 420 cl_event *event) { 421 CLOVER_NOT_SUPPORTED_UNTIL("1.2"); 422 return CL_INVALID_VALUE; 423 } 424