1 // 2 // Copyright (c) 2017 The Khronos Group Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 #ifndef _typeWrappers_h 17 #define _typeWrappers_h 18 19 #if !defined(_WIN32) 20 #include <sys/mman.h> 21 #endif 22 23 #include "compat.h" 24 #include "mt19937.h" 25 #include "errorHelpers.h" 26 #include "kernelHelpers.h" 27 28 #include <cstdlib> 29 #include <type_traits> 30 31 namespace wrapper_details { 32 33 // clRetain*() and clRelease*() functions share the same type. 34 template <typename T> // T should be cl_context, cl_program, ... 35 using RetainReleaseType = cl_int CL_API_CALL(T); 36 37 // A generic wrapper class that follows OpenCL retain/release semantics. 38 // 39 // This Wrapper class implement copy and move semantics, which makes it 40 // compatible with standard containers for example. 41 // 42 // Template parameters: 43 // - T is the cl_* type (e.g. cl_context, cl_program, ...) 44 // - Retain is the clRetain* function (e.g. clRetainContext, ...) 45 // - Release is the clRelease* function (e.g. clReleaseContext, ...) 46 template <typename T, RetainReleaseType<T> Retain, RetainReleaseType<T> Release> 47 class Wrapper { 48 static_assert(std::is_pointer<T>::value, "T should be a pointer type."); 49 T object = nullptr; 50 retain()51 void retain() 52 { 53 if (!object) return; 54 55 auto err = Retain(object); 56 if (err != CL_SUCCESS) 57 { 58 print_error(err, "clRetain*() failed"); 59 std::abort(); 60 } 61 } 62 release()63 void release() 64 { 65 if (!object) return; 66 67 auto err = Release(object); 68 if (err != CL_SUCCESS) 69 { 70 print_error(err, "clRelease*() failed"); 71 std::abort(); 72 } 73 } 74 75 public: 76 Wrapper() = default; 77 78 // On initialisation, assume the object has a refcount of one. Wrapper(T object)79 Wrapper(T object): object(object) {} 80 81 // On assignment, assume the object has a refcount of one. 82 Wrapper &operator=(T rhs) 83 { 84 reset(rhs); 85 return *this; 86 } 87 88 // Copy semantics, increase retain count. Wrapper(Wrapper const & w)89 Wrapper(Wrapper const &w) { *this = w; } 90 Wrapper &operator=(Wrapper const &w) 91 { 92 reset(w.object); 93 retain(); 94 return *this; 95 } 96 97 // Move semantics, directly take ownership. Wrapper(Wrapper && w)98 Wrapper(Wrapper &&w) { *this = std::move(w); } 99 Wrapper &operator=(Wrapper &&w) 100 { 101 reset(w.object); 102 w.object = nullptr; 103 return *this; 104 } 105 ~Wrapper()106 ~Wrapper() { reset(); } 107 108 // Release the existing object, if any, and own the new one, if any. 109 void reset(T new_object = nullptr) 110 { 111 release(); 112 object = new_object; 113 } 114 T()115 operator T() const { return object; } 116 117 // Ideally this function should not exist as it breaks encapsulation by 118 // allowing external mutation of the Wrapper internal state. However, too 119 // much code currently relies on this. For example, instead of using T* as 120 // output parameters, existing code can be updated to use Wrapper& instead. 121 T *operator&() { return &object; } 122 }; 123 124 } // namespace wrapper_details 125 126 using clContextWrapper = 127 wrapper_details::Wrapper<cl_context, clRetainContext, clReleaseContext>; 128 129 using clProgramWrapper = 130 wrapper_details::Wrapper<cl_program, clRetainProgram, clReleaseProgram>; 131 132 using clKernelWrapper = 133 wrapper_details::Wrapper<cl_kernel, clRetainKernel, clReleaseKernel>; 134 135 using clMemWrapper = 136 wrapper_details::Wrapper<cl_mem, clRetainMemObject, clReleaseMemObject>; 137 138 using clCommandQueueWrapper = 139 wrapper_details::Wrapper<cl_command_queue, clRetainCommandQueue, 140 clReleaseCommandQueue>; 141 142 using clSamplerWrapper = 143 wrapper_details::Wrapper<cl_sampler, clRetainSampler, clReleaseSampler>; 144 145 using clEventWrapper = 146 wrapper_details::Wrapper<cl_event, clRetainEvent, clReleaseEvent>; 147 148 class clSVMWrapper { 149 void *Ptr = nullptr; 150 cl_context Ctx = nullptr; 151 152 public: 153 clSVMWrapper() = default; 154 155 clSVMWrapper(cl_context C, size_t Size, 156 cl_svm_mem_flags F = CL_MEM_READ_WRITE) Ctx(C)157 : Ctx(C) 158 { 159 Ptr = clSVMAlloc(C, F, Size, 0); 160 } 161 162 clSVMWrapper &operator=(void *other) = delete; 163 clSVMWrapper(clSVMWrapper const &other) = delete; 164 clSVMWrapper &operator=(clSVMWrapper const &other) = delete; clSVMWrapper(clSVMWrapper && other)165 clSVMWrapper(clSVMWrapper &&other) 166 { 167 Ptr = other.Ptr; 168 Ctx = other.Ctx; 169 other.Ptr = nullptr; 170 other.Ctx = nullptr; 171 } 172 clSVMWrapper &operator=(clSVMWrapper &&other) 173 { 174 Ptr = other.Ptr; 175 Ctx = other.Ctx; 176 other.Ptr = nullptr; 177 other.Ctx = nullptr; 178 return *this; 179 } 180 ~clSVMWrapper()181 ~clSVMWrapper() 182 { 183 if (Ptr) clSVMFree(Ctx, Ptr); 184 } 185 operator()186 void *operator()() const { return Ptr; } 187 }; 188 189 190 class clProtectedImage { 191 public: clProtectedImage()192 clProtectedImage() 193 { 194 image = NULL; 195 backingStore = NULL; 196 } 197 clProtectedImage(cl_context context, cl_mem_flags flags, 198 const cl_image_format *fmt, size_t width, 199 cl_int *errcode_ret); 200 clProtectedImage(cl_context context, cl_mem_flags flags, 201 const cl_image_format *fmt, size_t width, size_t height, 202 cl_int *errcode_ret); 203 clProtectedImage(cl_context context, cl_mem_flags flags, 204 const cl_image_format *fmt, size_t width, size_t height, 205 size_t depth, cl_int *errcode_ret); 206 clProtectedImage(cl_context context, cl_mem_object_type imageType, 207 cl_mem_flags flags, const cl_image_format *fmt, 208 size_t width, size_t height, size_t depth, 209 size_t arraySize, cl_int *errcode_ret); ~clProtectedImage()210 ~clProtectedImage() 211 { 212 if (image != NULL) clReleaseMemObject(image); 213 214 #if defined(__APPLE__) 215 if (backingStore) munmap(backingStore, backingStoreSize); 216 #endif 217 } 218 219 cl_int Create(cl_context context, cl_mem_flags flags, 220 const cl_image_format *fmt, size_t width); 221 cl_int Create(cl_context context, cl_mem_flags flags, 222 const cl_image_format *fmt, size_t width, size_t height); 223 cl_int Create(cl_context context, cl_mem_flags flags, 224 const cl_image_format *fmt, size_t width, size_t height, 225 size_t depth); 226 cl_int Create(cl_context context, cl_mem_object_type imageType, 227 cl_mem_flags flags, const cl_image_format *fmt, size_t width, 228 size_t height, size_t depth, size_t arraySize); 229 230 clProtectedImage &operator=(const cl_mem &rhs) 231 { 232 image = rhs; 233 backingStore = NULL; 234 return *this; 235 } cl_mem()236 operator cl_mem() { return image; } 237 238 cl_mem *operator&() { return ℑ } 239 240 protected: 241 void *backingStore; 242 size_t backingStoreSize; 243 cl_mem image; 244 }; 245 246 /* Generic protected memory buffer, for verifying access within bounds */ 247 class clProtectedArray { 248 public: 249 clProtectedArray(); 250 clProtectedArray(size_t sizeInBytes); 251 virtual ~clProtectedArray(); 252 253 void Allocate(size_t sizeInBytes); 254 255 operator void *() { return (void *)mValidBuffer; } 256 operator const void *() const { return (const void *)mValidBuffer; } 257 258 protected: 259 char *mBuffer; 260 char *mValidBuffer; 261 size_t mRealSize, mRoundedSize; 262 }; 263 264 class RandomSeed { 265 public: RandomSeed(cl_uint seed)266 RandomSeed(cl_uint seed) 267 { 268 if (seed) log_info("(seed = %10.10u) ", seed); 269 mtData = init_genrand(seed); 270 } ~RandomSeed()271 ~RandomSeed() 272 { 273 if (gReSeed) gRandomSeed = genrand_int32(mtData); 274 free_mtdata(mtData); 275 } 276 MTdata()277 operator MTdata() { return mtData; } 278 279 protected: 280 MTdata mtData; 281 }; 282 283 284 template <typename T> class BufferOwningPtr { 285 BufferOwningPtr(BufferOwningPtr const &); // do not implement 286 void operator=(BufferOwningPtr const &); // do not implement 287 288 void *ptr; 289 void *map; 290 // Bytes allocated total, pointed to by map: 291 size_t mapsize; 292 // Bytes allocated in unprotected pages, pointed to by ptr: 293 size_t allocsize; 294 bool aligned; 295 296 public: 297 explicit BufferOwningPtr(void *p = 0) ptr(p)298 : ptr(p), map(0), mapsize(0), allocsize(0), aligned(false) 299 {} BufferOwningPtr(void * p,void * m,size_t s)300 explicit BufferOwningPtr(void *p, void *m, size_t s) 301 : ptr(p), map(m), mapsize(s), allocsize(0), aligned(false) 302 { 303 #if !defined(__APPLE__) 304 if (m) 305 { 306 log_error("ERROR: unhandled code path. BufferOwningPtr allocated " 307 "with mapped buffer!"); 308 abort(); 309 } 310 #endif 311 } ~BufferOwningPtr()312 ~BufferOwningPtr() 313 { 314 if (map) 315 { 316 #if defined(__APPLE__) 317 int error = munmap(map, mapsize); 318 if (error) 319 log_error("WARNING: munmap failed in BufferOwningPtr.\n"); 320 #endif 321 } 322 else 323 { 324 if (aligned) 325 { 326 align_free(ptr); 327 } 328 else 329 { 330 free(ptr); 331 } 332 } 333 } 334 void reset(void *p, void *m = 0, size_t mapsize_ = 0, size_t allocsize_ = 0, 335 bool aligned_ = false) 336 { 337 if (map) 338 { 339 #if defined(__APPLE__) 340 int error = munmap(map, mapsize); 341 if (error) 342 log_error("WARNING: munmap failed in BufferOwningPtr.\n"); 343 #else 344 log_error("ERROR: unhandled code path. BufferOwningPtr reset with " 345 "mapped buffer!"); 346 abort(); 347 #endif 348 } 349 else 350 { 351 if (aligned) 352 { 353 align_free(ptr); 354 } 355 else 356 { 357 free(ptr); 358 } 359 } 360 ptr = p; 361 map = m; 362 mapsize = mapsize_; 363 // Force allocsize to zero if ptr is NULL: 364 allocsize = (ptr != NULL) ? allocsize_ : 0; 365 aligned = aligned_; 366 #if !defined(__APPLE__) 367 if (m) 368 { 369 log_error("ERROR: unhandled code path. BufferOwningPtr allocated " 370 "with mapped buffer!"); 371 abort(); 372 } 373 #endif 374 } 375 operator T *() { return (T *)ptr; } 376 getSize()377 size_t getSize() const { return allocsize; }; 378 }; 379 380 #endif // _typeWrappers_h 381