1 module dcl.kernel; 2 3 import dcl.base; 4 import dcl.event; 5 import dcl.memory; 6 import dcl.commandqueue; 7 import dcl.program; 8 import dcl.device; 9 import dcl.context; 10 11 /// 12 class CLKernel : CLObject 13 { 14 package: 15 /// 16 cl_kernel id; 17 18 public: 19 20 /// 21 this( CLProgram program, string nm ) 22 { id = checkCode!clCreateKernel( program.id, nm.toStringz ); } 23 24 static private enum info_list = 25 [ 26 "string function_name:name", 27 "uint num_args", 28 "uint reference_count:refcount", 29 "cl_context:CLContext context", 30 "cl_program:CLProgram program", 31 "string attributes" 32 ]; 33 34 mixin( infoMixin( "kernel", info_list ) ); 35 36 protected: 37 38 override void selfDestroy() { checkCall!clReleaseKernel(id); } 39 } 40 41 /// 42 interface CLMemoryHandler 43 { 44 /// 45 protected CLMemory clmem() @property; 46 47 /// 48 /+ for post exec actions (release GL for example) 49 + save queue and add this to list (acquired list for example) 50 + before ocl operations process created list 51 +/ 52 void preSetAsKernelArg( CLCommandQueue ); 53 54 /// 55 mixin template CLMemoryHandlerHelper() 56 { 57 protected 58 { 59 CLMemory clmemory; 60 CLMemory clmem() @property { return clmemory; } 61 } 62 } 63 } 64 65 /// 66 struct CLKernelLocalMemory { size_t size; } 67 68 /// 69 auto clKernelLocalMemory(T=ubyte)( size_t count ) 70 { return CLKernelLocalMemory( T.sizeof * count ); } 71 72 /// 73 class CLKernelCaller 74 { 75 protected: 76 size_t[] offset; 77 size_t[] wgsize; 78 size_t[] lgsize; 79 80 uint range_dim = 1; 81 82 void setArray( ref size_t[] arr, size_t[] val ) 83 { 84 if( val ) 85 { 86 enforce( val.length >= range_dim ); 87 arr = val[0..range_dim].dup; 88 } 89 else arr = null; 90 } 91 92 public: 93 94 CLKernel kernel; 95 CLCommandQueue queue; 96 CLEvent exec_inst; 97 98 this( CLKernel kernel, CLCommandQueue queue ) 99 { 100 this.kernel = kernel; 101 this.queue = queue; 102 wgsize = [64]; 103 } 104 105 size_t rangeDim() const @property { return range_dim; } 106 void set1DRange() { range_dim = 1; } 107 void set2DRange() { range_dim = 2; } 108 void set3DRange() { range_dim = 3; } 109 110 void setGlobalOffset( size_t[] v... ) { setArray( offset, v ); } 111 void setWorkGroupSize( size_t[] v... ) { setArray( wgsize, v ); } 112 void setLocalGroupSize( size_t[] v... ) { setArray( lgsize, v ); } 113 114 /// 115 void setArgs(Args...)( Args args ) 116 { 117 foreach( i, arg; args ) 118 setArg( i, arg ); 119 } 120 121 /// 122 void range( CLEvent[] wait_list=[] ) 123 { 124 checkCallWL!clEnqueueNDRangeKernel( queue.id, kernel.id, 125 range_dim, offset.ptr, wgsize.ptr, lgsize.ptr, 126 wait_list, &exec_inst ); 127 } 128 129 /// 130 void task( CLEvent[] wait_list=[] ) 131 { 132 checkCallWL!clEnqueueTask( queue.id, kernel.id, wait_list, &exec_inst ); 133 } 134 135 static private enum info_list = 136 [ 137 "size_t work_group_size:max_work_group_size", 138 "size_t[3] compile_work_group_size", 139 "ulong local_mem_size", 140 "size_t preferred_work_group_size_multiple", 141 "ulong private_mem_size" 142 ]; 143 144 mixin( infoMixin( "kernel_work_group", "kernel", info_list, ["kernel","queue.device"] ) ); 145 146 protected: 147 148 /// 149 void setArg(Arg)( uint index, Arg arg ) 150 { 151 void *value; 152 size_t size; 153 154 static if( is( Arg : CLMemory ) ) 155 { 156 auto aid = arg ? (cast(CLMemory)arg).id : null; 157 value = &aid; 158 size = cl_mem.sizeof; 159 } 160 else static if( is( Arg : CLMemoryHandler ) ) 161 { 162 auto cmh = cast(CLMemoryHandler)arg; 163 cl_mem aid = null; 164 if( cmh !is null ) 165 { 166 cmh.preSetAsKernelArg( queue ); 167 aid = cmh.clmem.id; 168 } 169 value = &aid; 170 size = cl_mem.sizeof; 171 } 172 else static if( is( Arg == CLKernelLocalMemory )) 173 { 174 value = null; 175 size = arg.size; 176 } 177 else static if( !hasIndirections!Arg ) 178 { 179 value = &arg; 180 size = arg.sizeof; 181 } 182 else 183 { 184 pragma(msg, "type of ", Arg, " couldn't be set as kernel argument" ); 185 static assert(0); 186 } 187 188 checkCall!clSetKernelArg( kernel.id, index, size, value ); 189 } 190 }