• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &image; }
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