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 }