Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/android/tutorial-4-opencl/jni/CLprocessor.cpp
16348 views
1
#define __CL_ENABLE_EXCEPTIONS
2
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS /*let's give a chance for OpenCL 1.1 devices*/
3
#include <CL/cl.hpp>
4
5
#include <GLES2/gl2.h>
6
#include <EGL/egl.h>
7
8
#include <opencv2/core.hpp>
9
#include <opencv2/imgproc.hpp>
10
#include <opencv2/core/ocl.hpp>
11
12
#include "common.hpp"
13
14
const char oclProgB2B[] = "// clBuffer to clBuffer";
15
const char oclProgI2B[] = "// clImage to clBuffer";
16
const char oclProgI2I[] = \
17
"__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; \n" \
18
"\n" \
19
"__kernel void Laplacian( \n" \
20
" __read_only image2d_t imgIn, \n" \
21
" __write_only image2d_t imgOut \n" \
22
" ) { \n" \
23
" \n" \
24
" const int2 pos = {get_global_id(0), get_global_id(1)}; \n" \
25
" \n" \
26
" float4 sum = (float4) 0.0f; \n" \
27
" sum += read_imagef(imgIn, sampler, pos + (int2)(-1,0)); \n" \
28
" sum += read_imagef(imgIn, sampler, pos + (int2)(+1,0)); \n" \
29
" sum += read_imagef(imgIn, sampler, pos + (int2)(0,-1)); \n" \
30
" sum += read_imagef(imgIn, sampler, pos + (int2)(0,+1)); \n" \
31
" sum -= read_imagef(imgIn, sampler, pos) * 4; \n" \
32
" \n" \
33
" write_imagef(imgOut, pos, sum*10); \n" \
34
"} \n";
35
36
void dumpCLinfo()
37
{
38
LOGD("*** OpenCL info ***");
39
try
40
{
41
std::vector<cl::Platform> platforms;
42
cl::Platform::get(&platforms);
43
LOGD("OpenCL info: Found %d OpenCL platforms", platforms.size());
44
for (int i = 0; i < platforms.size(); ++i)
45
{
46
std::string name = platforms[i].getInfo<CL_PLATFORM_NAME>();
47
std::string version = platforms[i].getInfo<CL_PLATFORM_VERSION>();
48
std::string profile = platforms[i].getInfo<CL_PLATFORM_PROFILE>();
49
std::string extensions = platforms[i].getInfo<CL_PLATFORM_EXTENSIONS>();
50
LOGD( "OpenCL info: Platform[%d] = %s, ver = %s, prof = %s, ext = %s",
51
i, name.c_str(), version.c_str(), profile.c_str(), extensions.c_str() );
52
}
53
54
std::vector<cl::Device> devices;
55
platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices);
56
57
for (int i = 0; i < devices.size(); ++i)
58
{
59
std::string name = devices[i].getInfo<CL_DEVICE_NAME>();
60
std::string extensions = devices[i].getInfo<CL_DEVICE_EXTENSIONS>();
61
cl_ulong type = devices[i].getInfo<CL_DEVICE_TYPE>();
62
LOGD( "OpenCL info: Device[%d] = %s (%s), ext = %s",
63
i, name.c_str(), (type==CL_DEVICE_TYPE_GPU ? "GPU" : "CPU"), extensions.c_str() );
64
}
65
}
66
catch(cl::Error& e)
67
{
68
LOGE( "OpenCL info: error while gathering OpenCL info: %s (%d)", e.what(), e.err() );
69
}
70
catch(std::exception& e)
71
{
72
LOGE( "OpenCL info: error while gathering OpenCL info: %s", e.what() );
73
}
74
catch(...)
75
{
76
LOGE( "OpenCL info: unknown error while gathering OpenCL info" );
77
}
78
LOGD("*******************");
79
}
80
81
cl::Context theContext;
82
cl::CommandQueue theQueue;
83
cl::Program theProgB2B, theProgI2B, theProgI2I;
84
bool haveOpenCL = false;
85
86
extern "C" void initCL()
87
{
88
dumpCLinfo();
89
90
EGLDisplay mEglDisplay = eglGetCurrentDisplay();
91
if (mEglDisplay == EGL_NO_DISPLAY)
92
LOGE("initCL: eglGetCurrentDisplay() returned 'EGL_NO_DISPLAY', error = %x", eglGetError());
93
94
EGLContext mEglContext = eglGetCurrentContext();
95
if (mEglContext == EGL_NO_CONTEXT)
96
LOGE("initCL: eglGetCurrentContext() returned 'EGL_NO_CONTEXT', error = %x", eglGetError());
97
98
cl_context_properties props[] =
99
{ CL_GL_CONTEXT_KHR, (cl_context_properties) mEglContext,
100
CL_EGL_DISPLAY_KHR, (cl_context_properties) mEglDisplay,
101
CL_CONTEXT_PLATFORM, 0,
102
0 };
103
104
try
105
{
106
haveOpenCL = false;
107
cl::Platform p = cl::Platform::getDefault();
108
std::string ext = p.getInfo<CL_PLATFORM_EXTENSIONS>();
109
if(ext.find("cl_khr_gl_sharing") == std::string::npos)
110
LOGE("Warning: CL-GL sharing isn't supported by PLATFORM");
111
props[5] = (cl_context_properties) p();
112
113
theContext = cl::Context(CL_DEVICE_TYPE_GPU, props);
114
std::vector<cl::Device> devs = theContext.getInfo<CL_CONTEXT_DEVICES>();
115
LOGD("Context returned %d devices, taking the 1st one", devs.size());
116
ext = devs[0].getInfo<CL_DEVICE_EXTENSIONS>();
117
if(ext.find("cl_khr_gl_sharing") == std::string::npos)
118
LOGE("Warning: CL-GL sharing isn't supported by DEVICE");
119
120
theQueue = cl::CommandQueue(theContext, devs[0]);
121
122
cl::Program::Sources src(1, std::make_pair(oclProgI2I, sizeof(oclProgI2I)));
123
theProgI2I = cl::Program(theContext, src);
124
theProgI2I.build(devs);
125
126
cv::ocl::attachContext(p.getInfo<CL_PLATFORM_NAME>(), p(), theContext(), devs[0]());
127
if( cv::ocl::useOpenCL() )
128
LOGD("OpenCV+OpenCL works OK!");
129
else
130
LOGE("Can't init OpenCV with OpenCL TAPI");
131
haveOpenCL = true;
132
}
133
catch(cl::Error& e)
134
{
135
LOGE("cl::Error: %s (%d)", e.what(), e.err());
136
}
137
catch(std::exception& e)
138
{
139
LOGE("std::exception: %s", e.what());
140
}
141
catch(...)
142
{
143
LOGE( "OpenCL info: unknown error while initializing OpenCL stuff" );
144
}
145
LOGD("initCL completed");
146
}
147
148
extern "C" void closeCL()
149
{
150
}
151
152
#define GL_TEXTURE_2D 0x0DE1
153
void procOCL_I2I(int texIn, int texOut, int w, int h)
154
{
155
LOGD("Processing OpenCL Direct (image2d)");
156
if(!haveOpenCL)
157
{
158
LOGE("OpenCL isn't initialized");
159
return;
160
}
161
162
LOGD("procOCL_I2I(%d, %d, %d, %d)", texIn, texOut, w, h);
163
cl::ImageGL imgIn (theContext, CL_MEM_READ_ONLY, GL_TEXTURE_2D, 0, texIn);
164
cl::ImageGL imgOut(theContext, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, texOut);
165
std::vector < cl::Memory > images;
166
images.push_back(imgIn);
167
images.push_back(imgOut);
168
169
int64_t t = getTimeMs();
170
theQueue.enqueueAcquireGLObjects(&images);
171
theQueue.finish();
172
LOGD("enqueueAcquireGLObjects() costs %d ms", getTimeInterval(t));
173
174
t = getTimeMs();
175
cl::Kernel Laplacian(theProgI2I, "Laplacian"); //TODO: may be done once
176
Laplacian.setArg(0, imgIn);
177
Laplacian.setArg(1, imgOut);
178
theQueue.finish();
179
LOGD("Kernel() costs %d ms", getTimeInterval(t));
180
181
t = getTimeMs();
182
theQueue.enqueueNDRangeKernel(Laplacian, cl::NullRange, cl::NDRange(w, h), cl::NullRange);
183
theQueue.finish();
184
LOGD("enqueueNDRangeKernel() costs %d ms", getTimeInterval(t));
185
186
t = getTimeMs();
187
theQueue.enqueueReleaseGLObjects(&images);
188
theQueue.finish();
189
LOGD("enqueueReleaseGLObjects() costs %d ms", getTimeInterval(t));
190
}
191
192
void procOCL_OCV(int texIn, int texOut, int w, int h)
193
{
194
LOGD("Processing OpenCL via OpenCV");
195
if(!haveOpenCL)
196
{
197
LOGE("OpenCL isn't initialized");
198
return;
199
}
200
201
int64_t t = getTimeMs();
202
cl::ImageGL imgIn (theContext, CL_MEM_READ_ONLY, GL_TEXTURE_2D, 0, texIn);
203
std::vector < cl::Memory > images(1, imgIn);
204
theQueue.enqueueAcquireGLObjects(&images);
205
theQueue.finish();
206
cv::UMat uIn, uOut, uTmp;
207
cv::ocl::convertFromImage(imgIn(), uIn);
208
LOGD("loading texture data to OpenCV UMat costs %d ms", getTimeInterval(t));
209
theQueue.enqueueReleaseGLObjects(&images);
210
211
t = getTimeMs();
212
//cv::blur(uIn, uOut, cv::Size(5, 5));
213
cv::Laplacian(uIn, uTmp, CV_8U);
214
cv:multiply(uTmp, 10, uOut);
215
cv::ocl::finish();
216
LOGD("OpenCV processing costs %d ms", getTimeInterval(t));
217
218
t = getTimeMs();
219
cl::ImageGL imgOut(theContext, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, texOut);
220
images.clear();
221
images.push_back(imgOut);
222
theQueue.enqueueAcquireGLObjects(&images);
223
cl_mem clBuffer = (cl_mem)uOut.handle(cv::ACCESS_READ);
224
cl_command_queue q = (cl_command_queue)cv::ocl::Queue::getDefault().ptr();
225
size_t offset = 0;
226
size_t origin[3] = { 0, 0, 0 };
227
size_t region[3] = { w, h, 1 };
228
CV_Assert(clEnqueueCopyBufferToImage (q, clBuffer, imgOut(), offset, origin, region, 0, NULL, NULL) == CL_SUCCESS);
229
theQueue.enqueueReleaseGLObjects(&images);
230
cv::ocl::finish();
231
LOGD("uploading results to texture costs %d ms", getTimeInterval(t));
232
}
233
234
void drawFrameProcCPU(int w, int h, int texOut)
235
{
236
LOGD("Processing on CPU");
237
int64_t t;
238
239
// let's modify pixels in FBO texture in C++ code (on CPU)
240
static cv::Mat m;
241
m.create(h, w, CV_8UC4);
242
243
// read
244
t = getTimeMs();
245
// expecting FBO to be bound
246
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m.data);
247
LOGD("glReadPixels() costs %d ms", getTimeInterval(t));
248
249
// modify
250
t = getTimeMs();
251
cv::Laplacian(m, m, CV_8U);
252
m *= 10;
253
LOGD("Laplacian() costs %d ms", getTimeInterval(t));
254
255
// write back
256
glActiveTexture(GL_TEXTURE0);
257
glBindTexture(GL_TEXTURE_2D, texOut);
258
t = getTimeMs();
259
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m.data);
260
LOGD("glTexSubImage2D() costs %d ms", getTimeInterval(t));
261
}
262
263
264
enum ProcMode {PROC_MODE_NO_PROC=0, PROC_MODE_CPU=1, PROC_MODE_OCL_DIRECT=2, PROC_MODE_OCL_OCV=3};
265
266
extern "C" void processFrame(int tex1, int tex2, int w, int h, int mode)
267
{
268
switch(mode)
269
{
270
//case PROC_MODE_NO_PROC:
271
case PROC_MODE_CPU:
272
drawFrameProcCPU(w, h, tex2);
273
break;
274
case PROC_MODE_OCL_DIRECT:
275
procOCL_I2I(tex1, tex2, w, h);
276
break;
277
case PROC_MODE_OCL_OCV:
278
procOCL_OCV(tex1, tex2, w, h);
279
break;
280
default:
281
LOGE("Unexpected processing mode: %d", mode);
282
}
283
}
284
285