1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <clew/clew.h>
17 #include <sal/log.hxx>
19 #include <clew_setup.hxx>
23 // The purpose of this separate executable is to check whether OpenCL works
24 // without crashing (asserting, etc.). Other checks can be done by LO core itself.
26 #define check(value, expected) \
30 if (val != (expected)) \
33 "OpenCL driver check failed: " << val << "(line " << __LINE__ << ")"); \
37 #define openclcheck(value) check(value, CL_SUCCESS)
39 static void runTest(const char* deviceName
, const char* devicePlatform
)
41 int status
= clewInit(OPENCL_DLL_NAME
);
42 check(status
, CLEW_SUCCESS
);
44 // Find the given OpenCL device (in order to use the same one as LO core).
46 openclcheck(clGetPlatformIDs(0, nullptr, &numPlatforms
));
47 vector
<cl_platform_id
> platforms(numPlatforms
);
48 openclcheck(clGetPlatformIDs(numPlatforms
, platforms
.data(), nullptr));
49 cl_platform_id platformId
= nullptr;
50 for (cl_uint i
= 0; i
< numPlatforms
; ++i
)
52 char platformName
[64];
53 if (clGetPlatformInfo(platforms
[i
], CL_PLATFORM_NAME
, 64, platformName
, nullptr)
55 && strcmp(devicePlatform
, platformName
) == 0)
57 platformId
= platforms
[i
];
61 if (platformId
== nullptr)
63 SAL_WARN("opencl", "Device platform not found: " << devicePlatform
);
69 openclcheck(clGetDeviceIDs(platformId
, CL_DEVICE_TYPE_ALL
, 0, nullptr, &numDevices
));
70 vector
<cl_device_id
> devices(numDevices
);
72 clGetDeviceIDs(platformId
, CL_DEVICE_TYPE_ALL
, numDevices
, devices
.data(), nullptr));
73 cl_device_id deviceId
= nullptr;
74 for (cl_uint i
= 0; i
< numDevices
; ++i
)
77 if (clGetDeviceInfo(devices
[i
], CL_DEVICE_NAME
, 64, name
, nullptr) == CL_SUCCESS
78 && strcmp(deviceName
, name
) == 0)
80 deviceId
= devices
[i
];
84 if (deviceId
== nullptr)
86 SAL_WARN("opencl", "Device not found: " << deviceName
);
93 cl_context_properties cps
[3];
94 cps
[0] = CL_CONTEXT_PLATFORM
;
95 cps
[1] = reinterpret_cast<cl_context_properties
>(platformId
);
97 context
= clCreateContext(cps
, 1, &deviceId
, nullptr, nullptr, &state
);
99 cl_command_queue queue
= clCreateCommandQueue(context
, deviceId
, 0, &state
);
102 // Just a simple OpenCL program, the functionality or results do not really matter.
103 const char* source
[] = { "__kernel void testFunction( __global float* input1, __global float* "
104 "input2, __global float* output )"
106 " int gid0 = get_global_id( 0 );"
107 " output[ gid0 ] = input1[ gid0 ] * input2[ gid0 ];"
109 size_t sourceSize
[] = { strlen(source
[0]) };
110 cl_program program
= clCreateProgramWithSource(context
, 1, source
, sourceSize
, &state
);
112 state
= clBuildProgram(program
, 1, &deviceId
, nullptr, nullptr, nullptr);
114 if (state
!= CL_SUCCESS
)
118 = clGetProgramBuildInfo(program
, deviceId
, CL_PROGRAM_BUILD_LOG
, 0, nullptr, &length
);
119 vector
<char> error(length
+ 1);
120 status
= clGetProgramBuildInfo(program
, deviceId
, CL_PROGRAM_BUILD_LOG
, length
,
121 error
.data(), nullptr);
122 error
[length
] = '\0';
123 cerr
<< "OpenCL driver check build error:" << error
.data() << endl
;
128 cl_kernel kernel
= clCreateKernel(program
, "testFunction", &state
);
131 // Some random data for the program.
132 constexpr int dataSize
= 1000;
133 cl_float inputData1
[dataSize
];
134 cl_float inputData2
[dataSize
];
135 cl_float outputData
[dataSize
];
136 for (int i
= 0; i
< dataSize
; ++i
)
138 inputData1
[i
] = i
* 2;
139 inputData2
[i
] = i
% 100;
141 cl_mem input1
= clCreateBuffer(context
, CL_MEM_READ_ONLY
| CL_MEM_USE_HOST_PTR
,
142 sizeof(cl_float
) * dataSize
, inputData1
, &state
);
144 cl_mem input2
= clCreateBuffer(context
, CL_MEM_READ_ONLY
| CL_MEM_USE_HOST_PTR
,
145 sizeof(cl_float
) * dataSize
, inputData2
, &state
);
147 cl_mem output
= clCreateBuffer(context
, CL_MEM_WRITE_ONLY
| CL_MEM_USE_HOST_PTR
,
148 sizeof(cl_float
) * dataSize
, outputData
, &state
);
150 state
= clSetKernelArg(kernel
, 0, sizeof(cl_mem
), &input1
);
152 state
= clSetKernelArg(kernel
, 1, sizeof(cl_mem
), &input2
);
154 state
= clSetKernelArg(kernel
, 2, sizeof(cl_mem
), &output
);
157 const size_t globalWorkSize
[] = { dataSize
};
158 const size_t localSize
[1] = { 64 };
159 state
= clEnqueueNDRangeKernel(queue
, kernel
, 1, nullptr, globalWorkSize
, localSize
, 0, nullptr,
162 openclcheck(clFinish(queue
));
163 openclcheck(clEnqueueReadBuffer(queue
, output
, CL_TRUE
, 0, sizeof(cl_float
) * dataSize
,
164 outputData
, 0, nullptr, nullptr));
165 clReleaseMemObject(input1
);
166 clReleaseMemObject(input2
);
167 clReleaseMemObject(output
);
168 clReleaseKernel(kernel
);
169 clReleaseProgram(program
);
170 clReleaseCommandQueue(queue
);
171 clReleaseContext(context
);
174 int main(int argc
, char* argv
[])
178 runTest(argv
[1], argv
[2]);
179 // Always return exit code 0, LO itself can do error checking better, we just care
180 // if this helper crashes or not.
184 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */