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