-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCLExecute.hpp
292 lines (261 loc) · 7.68 KB
/
CLExecute.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#ifndef TCL_EXECUTE_HPP
#define TCL_EXECUTE_HPP
#include <typeinfo>
#include "CLInformation.hpp"
#include "CLSourceArray.hpp"
#include "CLExecuteProperty.hpp"
#include "CLDeviceInformation.hpp"
#include "CLWorkGroupSettings.hpp"
#include "CLBuffer.hpp"
namespace tcl
{
class CLExecute
{
private:
CLExecuteProperty executeProperty;
cl_event event;
unsigned argCount;
private:
void TestKernelArg(const cl_int& result) const
{
if (result != CL_SUCCESS)
{
switch (result)
{
case CL_INVALID_KERNEL:
throw CLException("無効なカーネルが指定されています");
case CL_INVALID_ARG_INDEX:
throw CLException("引数のインデックスが不正です");
case CL_INVALID_ARG_VALUE:
throw CLException("引数の値が不正です");
case CL_INVALID_MEM_OBJECT:
throw CLException("メモリオブジェクトが不正です");
case CL_INVALID_SAMPLER:
throw CLException("サンプラーオブジェクトが不正です");
case CL_INVALID_ARG_SIZE:
throw CLException("引数で指定したサイズが不正です");
case CL_OUT_OF_RESOURCES:
throw CLException("デバイス側のリソースを確保できませんでした");
case CL_OUT_OF_HOST_MEMORY:
throw CLException("ホスト側のリソースを確保できませんでした");
}
}
}
void TestEnqueueTask(const cl_int& result) const
{
if (result != CL_SUCCESS)
throw CLException("何かエラーが起きてタスクを実行できませんでした", result);
}
void TestNDRange(const cl_int& result) const
{
if (result != CL_SUCCESS)
{
switch (result)
{
case CL_INVALID_PROGRAM_EXECUTABLE:
throw CLException("コマンドキューに関連付けられた正常にビルドされたプログラムが存在しません");
case CL_INVALID_COMMAND_QUEUE:
throw CLException("コマンドキューが無効です");
case CL_INVALID_KERNEL:
throw CLException("カーネルが無効です");
case CL_INVALID_CONTEXT:
throw CLException("コンテキストが無効です");
case CL_INVALID_KERNEL_ARGS:
throw CLException("カーネル引数が指定されていません");
case CL_INVALID_WORK_DIMENSION:
throw CLException("カーネルの分割数が適切ではありません");
case CL_INVALID_GLOBAL_OFFSET:
throw CLException("オフセットの値がワークサイズを超えています");
case CL_INVALID_WORK_GROUP_SIZE:
throw CLException("ワークグループの大きさが不正です");
case CL_INVALID_WORK_ITEM_SIZE:
throw CLException("ワークアイテム数が不正です");
case CL_MISALIGNED_SUB_BUFFER_OFFSET:
throw CLException("サブバッファオフセットのアラインメントが不正です");
case CL_INVALID_IMAGE_SIZE:
throw CLException("カーネルに指定したイメージオブジェクトがデバイスでサポートされていません");
case CL_OUT_OF_RESOURCES:
throw CLException("カーネルの実行に必要なリソースが不足しています");
case CL_MEM_OBJECT_ALLOCATION_FAILURE:
throw CLException("メモリオブジェクトの領域を確保するのに失敗しました");
case CL_INVALID_EVENT_WAIT_LIST:
throw CLException("イベント待ちリストが不正です");
case CL_OUT_OF_HOST_MEMORY:
throw CLException("ホスト側のメモリのリソース確保に失敗しました");
}
}
}
public:
inline cl_command_queue& CommandQueue() {
return executeProperty.commandQueue;
}
inline cl_program& Program() {
return executeProperty.program;
}
inline cl_kernel& Kernel() {
return executeProperty.kernel;
}
public:
/**
* カーネルの実行やバッファの転送を管理する
* \param[in] info OpenCLの情報クラス
* \param[in] source ソースコード
* \param[in] useDeviceId利用したいデバイスID
*/
CLExecute(CLSource& source, const cl_device_id& useDeviceId)
: executeProperty(source, useDeviceId), argCount(0)
{
}
/**
* カーネルの実行やバッファの転送を管理する
* \param[in] info OpenCLの情報クラス
* \param[in] sourceArray ソースコードの配列クラス
* \param[in] useDeviceId 利用したいデバイスID
*/
CLExecute(CLSourceArray& sourceArray, const cl_device_id& useDeviceId)
: executeProperty(sourceArray, useDeviceId), argCount(0)
{
}
/**
* カーネルの実行やバッファの転送を管理する
* \param[in] info OpenCLの情報クラス
* \param[in] source ソースコード
* \param[in] device デバイス情報のインスタンス
*/
CLExecute(CLSource& source, const CLDeviceInformation& device)
: executeProperty(source, device.DeviceId()), argCount(0)
{
}
/**
* カーネルの実行やバッファの転送を管理する
* \param[in] info OpenCLの情報クラス
* \param[in] sourceArray ソースコードの配列クラス
* \param[in] device デバイス情報のインスタンス
*/
CLExecute(CLSourceArray& sourceArray, const CLDeviceInformation& device)
: executeProperty(sourceArray, device.DeviceId()), argCount(0)
{
}
/**
* カーネルに渡すための引数を設定する
* \param[in] buffer カーネルで利用するためのバッファ
*/
template <typename T>
CLExecute& SetArg(T& buffer)
{
#define TEST_BUFFER(X) typeid(buffer)==typeid(X)
// CLBufferを継承しているかどうか検証する
// いい方法があれば誰か教えて……
if (
TEST_BUFFER(CLReadWriteBuffer) ||
TEST_BUFFER(CLReadBuffer) ||
TEST_BUFFER(CLWriteBuffer) ||
TEST_BUFFER(CLBuffer))
#undef TEST_BUFFER
{
SetBuffer(buffer);
}
else
{
cl_int resultArg;
resultArg = clSetKernelArg(Kernel(), argCount++, sizeof(T), &buffer);
TestKernelArg(resultArg);
}
return *this;
}
/**
* カーネルに渡すための引数を差し替えor設定する
* \param argIndex 引数のインデックス
* \param buffer カーネルで利用したいバッファ
*/
template <typename T>
CLExecute& SetArg(const cl_uint argIndex, T& buffer)
{
const auto resultArg = clSetKernelArg(Kernel(), argIndex, sizeof(T), &buffer);
TestKernelArg(resultArg);
return *this;
}
/**
* カーネルに渡すための引数を設定する
* \param[in] buffer カーネルで利用するためのバッファ
* \param[in] otherBuffers 可変長引数
*/
template <typename T, typename... Args>
CLExecute& SetArg(T& buffer, Args&... otherBuffers)
{
if (typeid(buffer) == typeid(CLReadWriteBuffer))
SetBuffer(buffer);
else
SetArg(buffer);
argCount++;
SetArg(otherBuffers...);
argCount = 0;
return *this;
}
/**
* カーネルに渡すためのバッファを設定する
* \param[in] buffer CLBufferのインスタンス
*/
CLExecute& SetBuffer(CLBuffer& buffer)
{
const auto resultArg = clSetKernelArg(Kernel(), argCount++, sizeof(cl_mem), &buffer.Memory());
TestKernelArg(resultArg);
return *this;
}
/**
* カーネルに渡すためのバッファを引数番号を指定して設定する
* \param[in] argIndex 引数番号
* \param[in] buffer CLBufferのインスタンス
*/
CLExecute& SetBuffer(const cl_uint argIndex, CLBuffer& buffer)
{
const auto resultArg = clSetKernelArg(Kernel(), argIndex, sizeof(cl_mem), &buffer.Memory());
TestKernelArg(resultArg);
return *this;
}
/**
* カーネルに渡すためのバッファを設定する
* \param[in] buffer CLBufferのインスタンス
* \param[in] otherBuffers 同じ,CLBufferのインスタンス
*/
template <typename... Args>
CLExecute& SetBuffer(CLBuffer& buffer, Args&... otherBuffers)
{
SetBuffer(buffer);
argCount++;
SetBuffer(otherBuffers...);
argCount = 0;
return *this;
}
/**
* 単一のカーネルを実行させる
* \param[in] wait 実行終了まで待つかどうか
*/
CLExecute& Run()
{
auto resultTask = clEnqueueTask(CommandQueue(), Kernel(), 0, NULL, &event);
TestEnqueueTask(resultTask);
return *this;
}
/**
* 範囲指定してカーネルを実行する
* \param[in] setting 実行範囲を指定するクラスのインスタンス
* \param[in] wait 実行終了まで待つかどうか
*/
CLExecute& Run(CLWorkGroupSettings& setting)
{
auto result = clEnqueueNDRangeKernel(
CommandQueue(), Kernel(), setting.Dimension(),
setting.Offset(), setting.WorkerRange(), setting.SplitSize(),
0, NULL, &event);
TestNDRange(result);
return *this;
}
CLExecute& Wait()
{
clWaitForEvents(1, &event);
return *this;
}
};
}
#endif