-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
172 lines (150 loc) · 6.08 KB
/
main.cpp
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
#define CL_TARGET_OPENCL_VERSION 200
#include <CL/opencl.h>
#include <fmt/core.h>
#include <array>
#include <cstddef>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
int main(char** argv, int argc)
{
auto status = cl_int{};
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clGetPlatformIDs.html
// Query the number of platforms
auto num_platforms = cl_uint{};
status = clGetPlatformIDs(0, nullptr, &num_platforms);
if (status != CL_SUCCESS)
{
fmt::print("clGetPlatformIDs failed with error code {}\n", status);
return status;
}
// Query all the platforms
auto platforms = std::vector<cl_platform_id>(num_platforms);
status = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
if (status != CL_SUCCESS)
{
fmt::print("clGetPlatformIDs failed with error code {}\n", status);
return status;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clGetPlatformInfo.html
auto amd_platform = cl_platform_id{};
constexpr auto amd_platform_vendor = std::string_view{"Advanced Micro Devices, Inc."};
for (const auto &platform: platforms)
{
// Query the size of platform's vendor name
auto param_value_size = std::size_t{};
status = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, std::size_t{}, nullptr, ¶m_value_size);
if (status != CL_SUCCESS)
{
fmt::print("clGetPlatformInfo failed with error code {}\n", status);
return status;
}
// Query the platform's vendor name
auto platform_vendor = std::string{};
platform_vendor.resize(param_value_size);
status = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, platform_vendor.size(), platform_vendor.data(), nullptr);
if (status != CL_SUCCESS)
{
fmt::print("clGetPlatformInfo failed with error code {}\n", status);
return status;
}
// Remove extra trailing zeros
platform_vendor.erase(platform_vendor.find_last_not_of('\0') + 1, std::string::npos);
// Pick the AMD platform
if (platform_vendor == amd_platform_vendor)
{
amd_platform = platform;
break;
}
}
if (amd_platform == cl_platform_id{})
{
fmt::print("Could not find the AMD platform\n");
return -1;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clGetDeviceIDs.html
// Query the number of GPUs
auto num_devices = cl_uint{};
status = clGetDeviceIDs(amd_platform, CL_DEVICE_TYPE_GPU, cl_uint{}, nullptr, &num_devices);
if (status != CL_SUCCESS)
{
fmt::print("clGetDeviceIDs failed with error code {}\n", status);
return status;
}
// Query all the GPUs
auto devices = std::vector<cl_device_id>(num_devices);
status = clGetDeviceIDs(amd_platform, CL_DEVICE_TYPE_GPU, num_devices, devices.data(), nullptr);
if (status != CL_SUCCESS)
{
fmt::print("clGetDeviceIDs failed with error code {}\n", status);
return status;
}
// Pick first available device, for simplicity sake
const auto device = devices[0];
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clCreateContext.html
// Create a context on the default device
const auto context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &status);
if (status != CL_SUCCESS)
{
fmt::print("clCreateContext failed with error code {}\n", status);
return status;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clCreateProgramWithSource.html
// Create an OpenCL program
constexpr std::string_view hello_world =
#include "kernel.cl"
;
constexpr auto strings = std::array{hello_world.data()};
constexpr auto lengths = std::array{hello_world.size()};
const auto program = clCreateProgramWithSource(context, 1, const_cast<const char**>(strings.data()), lengths.data(), &status);
if (status != CL_SUCCESS)
{
fmt::print("clCreateProgramWithSource failed with error code {}\n", status);
return status;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clBuildProgram.html
// Build the OpenCL program
status = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
if (status != CL_SUCCESS)
{
fmt::print("clBuildProgram failed with error code {}\n", status);
return status;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clCreateKernel.html
// Extract the kernel from the program
const auto kernel = clCreateKernel(program, "hello_world", &status);
if (status != CL_SUCCESS)
{
fmt::print("clCreateKernel failed with error code {}\n", status);
return status;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clCreateCommandQueueWithProperties.html
// Create a queue
const auto queue = clCreateCommandQueueWithProperties(context, device, nullptr, &status);
if (status != CL_SUCCESS)
{
fmt::print("clCreateCommandQueueWithProperties failed with error code {}\n", status);
return status;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clEnqueueNDRangeKernel.html
// Enqueue the kernel
constexpr auto work_dim = cl_uint{3};
constexpr auto global_size = std::array<std::size_t, work_dim>{1, 1, 1};
constexpr auto local_size = std::array<std::size_t, work_dim>{1, 1, 1};
status = clEnqueueNDRangeKernel(queue, kernel, work_dim, nullptr, global_size.data(), local_size.data(), cl_uint{}, nullptr, nullptr);
if (status != CL_SUCCESS)
{
fmt::print("clEnqueueNDRangeKernel failed with error code {}\n", status);
return status;
}
// https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/clFinish.html
// Flush the queue and block
status = clFinish(queue);
if (status != CL_SUCCESS)
{
fmt::print("clEnqueueNDRangeKernel failed with error code {}\n", status);
return status;
}
return 0;
}