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 }