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 clProtectedImage { 149 public: clProtectedImage()150 clProtectedImage() 151 { 152 image = NULL; 153 backingStore = NULL; 154 } 155 clProtectedImage(cl_context context, cl_mem_flags flags, 156 const cl_image_format *fmt, size_t width, 157 cl_int *errcode_ret); 158 clProtectedImage(cl_context context, cl_mem_flags flags, 159 const cl_image_format *fmt, size_t width, size_t height, 160 cl_int *errcode_ret); 161 clProtectedImage(cl_context context, cl_mem_flags flags, 162 const cl_image_format *fmt, size_t width, size_t height, 163 size_t depth, cl_int *errcode_ret); 164 clProtectedImage(cl_context context, cl_mem_object_type imageType, 165 cl_mem_flags flags, const cl_image_format *fmt, 166 size_t width, size_t height, size_t depth, 167 size_t arraySize, cl_int *errcode_ret); ~clProtectedImage()168 ~clProtectedImage() 169 { 170 if (image != NULL) clReleaseMemObject(image); 171 172 #if defined(__APPLE__) 173 if (backingStore) munmap(backingStore, backingStoreSize); 174 #endif 175 } 176 177 cl_int Create(cl_context context, cl_mem_flags flags, 178 const cl_image_format *fmt, size_t width); 179 cl_int Create(cl_context context, cl_mem_flags flags, 180 const cl_image_format *fmt, size_t width, size_t height); 181 cl_int Create(cl_context context, cl_mem_flags flags, 182 const cl_image_format *fmt, size_t width, size_t height, 183 size_t depth); 184 cl_int Create(cl_context context, cl_mem_object_type imageType, 185 cl_mem_flags flags, const cl_image_format *fmt, size_t width, 186 size_t height, size_t depth, size_t arraySize); 187 188 clProtectedImage &operator=(const cl_mem &rhs) 189 { 190 image = rhs; 191 backingStore = NULL; 192 return *this; 193 } cl_mem()194 operator cl_mem() { return image; } 195 196 cl_mem *operator&() { return ℑ } 197 198 protected: 199 void *backingStore; 200 size_t backingStoreSize; 201 cl_mem image; 202 }; 203 204 /* Generic protected memory buffer, for verifying access within bounds */ 205 class clProtectedArray { 206 public: 207 clProtectedArray(); 208 clProtectedArray(size_t sizeInBytes); 209 virtual ~clProtectedArray(); 210 211 void Allocate(size_t sizeInBytes); 212 213 operator void *() { return (void *)mValidBuffer; } 214 operator const void *() const { return (const void *)mValidBuffer; } 215 216 protected: 217 char *mBuffer; 218 char *mValidBuffer; 219 size_t mRealSize, mRoundedSize; 220 }; 221 222 class RandomSeed { 223 public: RandomSeed(cl_uint seed)224 RandomSeed(cl_uint seed) 225 { 226 if (seed) log_info("(seed = %10.10u) ", seed); 227 mtData = init_genrand(seed); 228 } ~RandomSeed()229 ~RandomSeed() 230 { 231 if (gReSeed) gRandomSeed = genrand_int32(mtData); 232 free_mtdata(mtData); 233 } 234 MTdata()235 operator MTdata() { return mtData; } 236 237 protected: 238 MTdata mtData; 239 }; 240 241 242 template <typename T> class BufferOwningPtr { 243 BufferOwningPtr(BufferOwningPtr const &); // do not implement 244 void operator=(BufferOwningPtr const &); // do not implement 245 246 void *ptr; 247 void *map; 248 // Bytes allocated total, pointed to by map: 249 size_t mapsize; 250 // Bytes allocated in unprotected pages, pointed to by ptr: 251 size_t allocsize; 252 bool aligned; 253 254 public: 255 explicit BufferOwningPtr(void *p = 0) ptr(p)256 : ptr(p), map(0), mapsize(0), allocsize(0), aligned(false) 257 {} BufferOwningPtr(void * p,void * m,size_t s)258 explicit BufferOwningPtr(void *p, void *m, size_t s) 259 : ptr(p), map(m), mapsize(s), allocsize(0), aligned(false) 260 { 261 #if !defined(__APPLE__) 262 if (m) 263 { 264 log_error("ERROR: unhandled code path. BufferOwningPtr allocated " 265 "with mapped buffer!"); 266 abort(); 267 } 268 #endif 269 } ~BufferOwningPtr()270 ~BufferOwningPtr() 271 { 272 if (map) 273 { 274 #if defined(__APPLE__) 275 int error = munmap(map, mapsize); 276 if (error) 277 log_error("WARNING: munmap failed in BufferOwningPtr.\n"); 278 #endif 279 } 280 else 281 { 282 if (aligned) 283 { 284 align_free(ptr); 285 } 286 else 287 { 288 free(ptr); 289 } 290 } 291 } 292 void reset(void *p, void *m = 0, size_t mapsize_ = 0, size_t allocsize_ = 0, 293 bool aligned_ = false) 294 { 295 if (map) 296 { 297 #if defined(__APPLE__) 298 int error = munmap(map, mapsize); 299 if (error) 300 log_error("WARNING: munmap failed in BufferOwningPtr.\n"); 301 #else 302 log_error("ERROR: unhandled code path. BufferOwningPtr reset with " 303 "mapped buffer!"); 304 abort(); 305 #endif 306 } 307 else 308 { 309 if (aligned) 310 { 311 align_free(ptr); 312 } 313 else 314 { 315 free(ptr); 316 } 317 } 318 ptr = p; 319 map = m; 320 mapsize = mapsize_; 321 // Force allocsize to zero if ptr is NULL: 322 allocsize = (ptr != NULL) ? allocsize_ : 0; 323 aligned = aligned_; 324 #if !defined(__APPLE__) 325 if (m) 326 { 327 log_error("ERROR: unhandled code path. BufferOwningPtr allocated " 328 "with mapped buffer!"); 329 abort(); 330 } 331 #endif 332 } 333 operator T *() { return (T *)ptr; } 334 getSize()335 size_t getSize() const { return allocsize; }; 336 }; 337 338 #endif // _typeWrappers_h 339