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>
21 // The purpose of this separate executable is to check whether OpenCL works
22 // without crashing (asserting, etc.). Other checks can be done by LO core itself.
24 #define check(value, expected) \
28 if (val != (expected)) \
31 "OpenCL driver check failed: " << val << "(line " << __LINE__ << ")"); \
35 #define openclcheck(value) check(value, CL_SUCCESS)
37 static void runTest(const char* deviceName
, const char* devicePlatform
)
39 int status
= clewInit(OPENCL_DLL_NAME
);
40 check(status
, CLEW_SUCCESS
);
42 // Find the given OpenCL device (in order to use the same one as LO core).
44 openclcheck(clGetPlatformIDs(0, nullptr, &numPlatforms
));
45 std::vector
<cl_platform_id
> platforms(numPlatforms
);
46 openclcheck(clGetPlatformIDs(numPlatforms
, platforms
.data(), nullptr));
47 cl_platform_id platformId
= nullptr;
48 for (cl_uint i
= 0; i
< numPlatforms
; ++i
)
50 char platformName
[64];
51 if (clGetPlatformInfo(platforms
[i
], CL_PLATFORM_NAME
, 64, platformName
, nullptr)
53 && strcmp(devicePlatform
, platformName
) == 0)
55 platformId
= platforms
[i
];
59 if (platformId
== nullptr)
61 SAL_WARN("opencl", "Device platform not found: " << devicePlatform
);
67 openclcheck(clGetDeviceIDs(platformId
, CL_DEVICE_TYPE_ALL
, 0, nullptr, &numDevices
));
68 std::vector
<cl_device_id
> devices(numDevices
);
70 clGetDeviceIDs(platformId
, CL_DEVICE_TYPE_ALL
, numDevices
, devices
.data(), nullptr));
71 cl_device_id deviceId
= nullptr;
72 for (cl_uint i
= 0; i
< numDevices
; ++i
)
75 if (clGetDeviceInfo(devices
[i
], CL_DEVICE_NAME
, 64, name
, nullptr) == CL_SUCCESS
76 && strcmp(deviceName
, name
) == 0)
78 deviceId
= devices
[i
];
82 if (deviceId
== nullptr)
84 SAL_WARN("opencl", "Device not found: " << deviceName
);
91 cl_context_properties cps
[3];
92 cps
[0] = CL_CONTEXT_PLATFORM
;
93 cps
[1] = reinterpret_cast<cl_context_properties
>(platformId
);
95 context
= clCreateContext(cps
, 1, &deviceId
, nullptr, nullptr, &state
);
97 cl_command_queue queue
= clCreateCommandQueue(context
, deviceId
, 0, &state
);
100 // Just a simple OpenCL program, the functionality or results do not really matter.
101 const char* source
[] = { "__kernel void testFunction( __global float* input1, __global float* "
102 "input2, __global float* output )"
104 " int gid0 = get_global_id( 0 );"
105 " output[ gid0 ] = input1[ gid0 ] * input2[ gid0 ];"
107 size_t sourceSize
[] = { strlen(source
[0]) };
108 cl_program program
= clCreateProgramWithSource(context
, 1, source
, sourceSize
, &state
);
110 state
= clBuildProgram(program
, 1, &deviceId
, nullptr, nullptr, nullptr);
112 if (state
!= CL_SUCCESS
)
116 = clGetProgramBuildInfo(program
, deviceId
, CL_PROGRAM_BUILD_LOG
, 0, nullptr, &length
);
117 std::vector
<char> error(length
+ 1);
118 status
= clGetProgramBuildInfo(program
, deviceId
, CL_PROGRAM_BUILD_LOG
, length
,
119 error
.data(), nullptr);
120 error
[length
] = '\0';
121 std::cerr
<< "OpenCL driver check build error:" << error
.data() << std::endl
;
126 cl_kernel kernel
= clCreateKernel(program
, "testFunction", &state
);
129 // Some random data for the program.
130 constexpr int dataSize
= 1000;
131 cl_float inputData1
[dataSize
];
132 cl_float inputData2
[dataSize
];
133 cl_float outputData
[dataSize
];
134 for (int i
= 0; i
< dataSize
; ++i
)
136 inputData1
[i
] = i
* 2;
137 inputData2
[i
] = i
% 100;
139 cl_mem input1
= clCreateBuffer(context
, CL_MEM_READ_ONLY
| CL_MEM_USE_HOST_PTR
,
140 sizeof(cl_float
) * dataSize
, inputData1
, &state
);
142 cl_mem input2
= clCreateBuffer(context
, CL_MEM_READ_ONLY
| CL_MEM_USE_HOST_PTR
,
143 sizeof(cl_float
) * dataSize
, inputData2
, &state
);
145 cl_mem output
= clCreateBuffer(context
, CL_MEM_WRITE_ONLY
| CL_MEM_USE_HOST_PTR
,
146 sizeof(cl_float
) * dataSize
, outputData
, &state
);
148 state
= clSetKernelArg(kernel
, 0, sizeof(cl_mem
), &input1
);
150 state
= clSetKernelArg(kernel
, 1, sizeof(cl_mem
), &input2
);
152 state
= clSetKernelArg(kernel
, 2, sizeof(cl_mem
), &output
);
155 const size_t globalWorkSize
[] = { dataSize
};
156 const size_t localSize
[1] = { 64 };
157 state
= clEnqueueNDRangeKernel(queue
, kernel
, 1, nullptr, globalWorkSize
, localSize
, 0, nullptr,
160 openclcheck(clFinish(queue
));
161 openclcheck(clEnqueueReadBuffer(queue
, output
, CL_TRUE
, 0, sizeof(cl_float
) * dataSize
,
162 outputData
, 0, nullptr, nullptr));
163 clReleaseMemObject(input1
);
164 clReleaseMemObject(input2
);
165 clReleaseMemObject(output
);
166 clReleaseKernel(kernel
);
167 clReleaseProgram(program
);
168 clReleaseCommandQueue(queue
);
169 clReleaseContext(context
);
172 int main(int argc
, char* argv
[])
176 runTest(argv
[1], argv
[2]);
177 // Always return exit code 0, LO itself can do error checking better, we just care
178 // if this helper crashes or not.
182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */