1 /++ base classes, functions, public imports,
2 
3     `loadCL` load DerelictCL with version 1.2
4  +/
5 module dcl.base;
6 
7 public import derelict.opencl.cl;
8 public import dcl.error;
9 
10 package
11 {
12     import std..string;
13     import std.traits;
14     import std.range;
15     import std.algorithm;
16     import std.array;
17     import std.exception;
18 
19     import dcl.util;
20     import dcl.event;
21 }
22 
23 ///
24 extern(C)
25 void loadCL()
26 {
27     if( !DerelictCL.isLoaded ) DerelictCL.load();
28     DerelictCL.reload( CLVersion.CL12 );
29 }
30 
31 import std.meta;
32 class CLObject
33 {
34     protected
35     {
36         CLObject parent;
37         Object[] child;
38     }
39 
40     auto regChild(T)( T[] arr )
41     {
42         foreach( obj; arr ) regChild( obj );
43         return arr;
44     }
45 
46     auto regChild(T)( T obj ) if( !isArray!T )
47     {
48         static if( is( T : CLObject ) )
49             enforce( noLoop( obj ), "has loop" );
50         child ~= obj;
51         return obj;
52     }
53 
54     auto newChild(T,Args...)( Args args )
55     { return regChild( new T(args) ); }
56 
57     void preChildDestory(){}
58     void selfDestroy(){}
59 
60     ~this()
61     {
62         preChildDestory();
63         foreach( ch; child )
64             ch.destroy();
65         selfDestroy();
66     }
67 
68 private:
69 
70     bool noLoop( CLObject[] arr... )
71     {
72         foreach( obj; arr )
73             if( obj is this || !noLoop(obj.child.map!(a=>cast(CLObject)a).filter!(a=>a !is null).array) )
74                 return false;
75         return true;
76     }
77 }
78 
79 unittest
80 {
81     import std.exception;
82 
83     auto a = new CLObject;
84     auto b = a.newChild!CLObject;
85     auto c = a.newChild!CLObject;
86     b.regChild(c);
87 
88     assertThrown( b.regChild(a) );
89     assertThrown( b.regChild([c,a]) );
90 
91     a.destroy();
92     b.destroy();
93     c.destroy();
94 }
95 
96 package
97 {
98     ///
99     auto getIDsPtr(T)( T[] list... ) pure { return map!(a=>a.id)(list).array.ptr; }
100 
101     ///
102     auto buildFlags(T=uint)( T[] list... ) pure { return reduce!((a,b)=>a|=b)(T(0),list); }
103 
104     unittest
105     {
106         assert( buildFlags( 0b01, 0b10 ) == 0b11 );
107         assert( buildFlags() == 0 );
108     }
109 
110     ///
111     auto parseFlags(T)( ulong mask, T[] without=[] )
112     {
113         T[] ret;
114         foreach( v; [EnumMembers!T] )
115         {
116             if( without.canFind(v) ) continue;
117             if( mask & cast(ulong)v )
118                 ret ~= v;
119         }
120         return ret;
121     }
122 
123     unittest
124     {
125         enum TT
126         {
127             ONE = 1<<0,
128             TWO = 1<<1,
129             THR = 1<<2,
130             FOU = 1<<3
131         }
132 
133         auto mask = buildFlags( TT.ONE, TT.THR );
134         auto tt = parseFlags!TT( mask );
135         assert( tt == [ TT.ONE, TT.THR ] );
136     }
137 
138     /// check error code and throw exception if it not `CL_SUCCESS`
139     void checkError( int code, lazy string fnc, lazy string[2][] args,
140                      lazy string file=__FILE__, lazy size_t line=__LINE__ )
141     {
142         auto err = cast(CLError)code;
143         if( err == CLError.NONE ) return;
144         throw new CLCallException( fnc, args, err, file, line );
145     }
146 
147     /++ check OpenCL `fnc` return value
148      +  calls `fnc( args )`
149      +/
150     void checkCall(alias fnc, string file=__FILE__, size_t line=__LINE__, Args...)( Args args )
151     { checkError( fnc( args ), (&fnc).stringof[2..$], argsToStringArray(args), file, line ); }
152 
153     /++ check OpenCL `fnc` return value
154      +  easy wait_list and event passes
155      +  see_also: `checkCall`
156      +/
157     void checkCallWL(alias fnc, string file=__FILE__, size_t line=__LINE__, Args...)( Args args )
158     {
159         static assert( is( Args[$-1] : CLEvent* ) );
160         static assert( is( Args[$-2] : CLEvent[] ) );
161         auto wl = args[$-2];
162         auto ev = args[$-1];
163         checkCall!(fnc,file,line)( args[0..$-2],
164                 cast(uint)wl.length, cast(cl_event*)wl.ptr, cast(cl_event*)ev );
165     }
166 
167     /++ check error code after OpenCL `fnc` call
168      + calls `fnc( args, &retcode )`
169      + Returns:
170      + result of `fnc` call
171      +/
172     auto checkCode(alias fnc, string file=__FILE__, size_t line=__LINE__, Args...)( Args args )
173     {
174         int retcode;
175         debug
176         {
177             auto id = fnc( args, &retcode );
178             checkError( retcode, (&fnc).stringof[2..$], argsToStringArray(args), file, line );
179             return id;
180         }
181         else
182         {
183             scope(exit) checkError( retcode, (&fnc).stringof[2..$], argsToStringArray(args), file, line );
184             return fnc( args, &retcode );
185         }
186     }
187 
188     /++ check error code after OpenCL `fnc` call
189      +  easy wait_list and event passes
190      +  see_also: `checkCode`
191      +/
192     auto checkCodeWL(alias fnc, string file=__FILE__, size_t line=__LINE__, Args...)( Args args )
193     {
194         static assert( is( Args[$-1] : CLEvent* ) );
195         static assert( is( Args[$-2] : CLEvent[] ) );
196         auto wl = args[$-2];
197         auto ev = args[$-1];
198         return checkCode!(fnc,file,line)( args[0..$-2],
199                 cast(uint)wl.length, cast(cl_event*)wl.ptr, cast(cl_event*)ev );
200     }
201 
202     string[2][] argsToStringArray(Args...)( Args args )
203     {
204         static if( Args.length > 1 )
205             return argsToStringArray( args[0..$/2] ) ~ argsToStringArray( args[$/2..$] );
206         else
207         {
208             enum tname = Args[0].stringof;
209             static if( isIntegral!(Args[0]) )
210                 return [ [ tname, format( "%1$d (0x%1$x)", args[0] ) ] ];
211             else
212                 return [ [ tname, format( "%s", args[0] ) ] ];
213         }
214     }
215 }