Merge branch 'master' into blender2.8
[blender.git] / intern / cycles / device / device_opencl.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifdef WITH_OPENCL
18
19 #include "device/opencl/opencl.h"
20
21 #include "device/device_intern.h"
22
23 #include "util/util_foreach.h"
24 #include "util/util_logging.h"
25 #include "util/util_set.h"
26 #include "util/util_string.h"
27
28 CCL_NAMESPACE_BEGIN
29
30 Device *device_opencl_create(DeviceInfo& info, Stats &stats, bool background)
31 {
32         vector<OpenCLPlatformDevice> usable_devices;
33         OpenCLInfo::get_usable_devices(&usable_devices);
34         assert(info.num < usable_devices.size());
35         const OpenCLPlatformDevice& platform_device = usable_devices[info.num];
36         const string& platform_name = platform_device.platform_name;
37         const cl_device_type device_type = platform_device.device_type;
38         if(OpenCLInfo::kernel_use_split(platform_name, device_type)) {
39                 VLOG(1) << "Using split kernel.";
40                 return opencl_create_split_device(info, stats, background);
41         } else {
42                 VLOG(1) << "Using mega kernel.";
43                 return opencl_create_mega_device(info, stats, background);
44         }
45 }
46
47 bool device_opencl_init(void)
48 {
49         static bool initialized = false;
50         static bool result = false;
51
52         if(initialized)
53                 return result;
54
55         initialized = true;
56
57         if(OpenCLInfo::device_type() != 0) {
58                 int clew_result = clewInit();
59                 if(clew_result == CLEW_SUCCESS) {
60                         VLOG(1) << "CLEW initialization succeeded.";
61                         result = true;
62                 }
63                 else {
64                         VLOG(1) << "CLEW initialization failed: "
65                                 << ((clew_result == CLEW_ERROR_ATEXIT_FAILED)
66                                     ? "Error setting up atexit() handler"
67                                     : "Error opening the library");
68                 }
69         }
70         else {
71                 VLOG(1) << "Skip initializing CLEW, platform is force disabled.";
72                 result = false;
73         }
74
75         return result;
76 }
77
78
79 static cl_int device_opencl_get_num_platforms_safe(cl_uint *num_platforms)
80 {
81 #ifdef _WIN32
82         __try {
83                 return clGetPlatformIDs(0, NULL, num_platforms);
84         }
85         __except(EXCEPTION_EXECUTE_HANDLER) {
86                 /* Ignore crashes inside the OpenCL driver and hope we can
87                  * survive even with corrupted OpenCL installs. */
88                 fprintf(stderr, "Cycles OpenCL: driver crashed, continuing without OpenCL.\n");
89         }
90
91         *num_platforms = 0;
92         return CL_DEVICE_NOT_FOUND;
93 #else
94         return clGetPlatformIDs(0, NULL, num_platforms);
95 #endif
96 }
97
98 void device_opencl_info(vector<DeviceInfo>& devices)
99 {
100         cl_uint num_platforms = 0;
101         device_opencl_get_num_platforms_safe(&num_platforms);
102         if(num_platforms == 0) {
103                 return;
104         }
105
106         vector<OpenCLPlatformDevice> usable_devices;
107         OpenCLInfo::get_usable_devices(&usable_devices);
108         /* Devices are numbered consecutively across platforms. */
109         int num_devices = 0;
110         set<string> unique_ids;
111         foreach(OpenCLPlatformDevice& platform_device, usable_devices) {
112                 /* Compute unique ID for persistent user preferences. */
113                 const string& platform_name = platform_device.platform_name;
114                 const cl_device_type device_type = platform_device.device_type;
115                 const string& device_name = platform_device.device_name;
116                 string hardware_id = platform_device.hardware_id;
117                 if(hardware_id == "") {
118                         hardware_id = string_printf("ID_%d", num_devices);
119                 }
120                 string id = string("OPENCL_") + platform_name + "_" + device_name + "_" + hardware_id;
121
122                 /* Hardware ID might not be unique, add device number in that case. */
123                 if(unique_ids.find(id) != unique_ids.end()) {
124                         id += string_printf("_ID_%d", num_devices);
125                 }
126                 unique_ids.insert(id);
127
128                 /* Create DeviceInfo. */
129                 DeviceInfo info;
130                 info.type = DEVICE_OPENCL;
131                 info.description = string_remove_trademark(string(device_name));
132                 info.num = num_devices;
133                 /* We don't know if it's used for display, but assume it is. */
134                 info.display_device = true;
135                 info.advanced_shading = OpenCLInfo::kernel_use_advanced_shading(platform_name);
136                 info.use_split_kernel = OpenCLInfo::kernel_use_split(platform_name,
137                                                                      device_type);
138                 info.has_volume_decoupled = false;
139                 info.bvh_layout_mask = BVH_LAYOUT_BVH2;
140                 info.id = id;
141
142                 /* Check OpenCL extensions */
143                 info.has_half_images = platform_device.device_extensions.find("cl_khr_fp16") != string::npos;
144
145                 devices.push_back(info);
146                 num_devices++;
147         }
148 }
149
150 string device_opencl_capabilities(void)
151 {
152         if(OpenCLInfo::device_type() == 0) {
153                 return "All OpenCL devices are forced to be OFF";
154         }
155         string result = "";
156         string error_msg = "";  /* Only used by opencl_assert(), but in the future
157                                  * it could also be nicely reported to the console.
158                                  */
159         cl_uint num_platforms = 0;
160         opencl_assert(device_opencl_get_num_platforms_safe(&num_platforms));
161         if(num_platforms == 0) {
162                 return "No OpenCL platforms found\n";
163         }
164         result += string_printf("Number of platforms: %u\n", num_platforms);
165
166         vector<cl_platform_id> platform_ids;
167         platform_ids.resize(num_platforms);
168         opencl_assert(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
169
170         typedef char cl_string[1024];
171
172 #define APPEND_INFO(func, id, name, what, type) \
173         do { \
174                 type data; \
175                 memset(&data, 0, sizeof(data)); \
176                 opencl_assert(func(id, what, sizeof(data), &data, NULL)); \
177                 result += string_printf("%s: %s\n", name, to_string(data).c_str()); \
178         } while(false)
179 #define APPEND_STRING_EXTENSION_INFO(func, id, name, what) \
180         do { \
181                 char data[1024] = "\0"; \
182                 size_t length = 0; \
183                 if(func(id, what, sizeof(data), &data, &length) == CL_SUCCESS) { \
184                         if(length != 0 && data[0] != '\0') { \
185                                 result += string_printf("%s: %s\n", name, data); \
186                         } \
187                 } \
188         } while(false)
189 #define APPEND_PLATFORM_INFO(id, name, what, type) \
190         APPEND_INFO(clGetPlatformInfo, id, "\tPlatform " name, what, type)
191 #define APPEND_DEVICE_INFO(id, name, what, type) \
192         APPEND_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what, type)
193 #define APPEND_DEVICE_STRING_EXTENSION_INFO(id, name, what) \
194         APPEND_STRING_EXTENSION_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what)
195
196         vector<cl_device_id> device_ids;
197         for(cl_uint platform = 0; platform < num_platforms; ++platform) {
198                 cl_platform_id platform_id = platform_ids[platform];
199
200                 result += string_printf("Platform #%u\n", platform);
201
202                 APPEND_PLATFORM_INFO(platform_id, "Name", CL_PLATFORM_NAME, cl_string);
203                 APPEND_PLATFORM_INFO(platform_id, "Vendor", CL_PLATFORM_VENDOR, cl_string);
204                 APPEND_PLATFORM_INFO(platform_id, "Version", CL_PLATFORM_VERSION, cl_string);
205                 APPEND_PLATFORM_INFO(platform_id, "Profile", CL_PLATFORM_PROFILE, cl_string);
206                 APPEND_PLATFORM_INFO(platform_id, "Extensions", CL_PLATFORM_EXTENSIONS, cl_string);
207
208                 cl_uint num_devices = 0;
209                 opencl_assert(clGetDeviceIDs(platform_ids[platform],
210                                              CL_DEVICE_TYPE_ALL,
211                                              0,
212                                              NULL,
213                                              &num_devices));
214                 result += string_printf("\tNumber of devices: %u\n", num_devices);
215
216                 device_ids.resize(num_devices);
217                 opencl_assert(clGetDeviceIDs(platform_ids[platform],
218                                              CL_DEVICE_TYPE_ALL,
219                                              num_devices,
220                                              &device_ids[0],
221                                              NULL));
222                 for(cl_uint device = 0; device < num_devices; ++device) {
223                         cl_device_id device_id = device_ids[device];
224
225                         result += string_printf("\t\tDevice: #%u\n", device);
226
227                         APPEND_DEVICE_INFO(device_id, "Name", CL_DEVICE_NAME, cl_string);
228                         APPEND_DEVICE_STRING_EXTENSION_INFO(device_id, "Board Name", CL_DEVICE_BOARD_NAME_AMD);
229                         APPEND_DEVICE_INFO(device_id, "Vendor", CL_DEVICE_VENDOR, cl_string);
230                         APPEND_DEVICE_INFO(device_id, "OpenCL C Version", CL_DEVICE_OPENCL_C_VERSION, cl_string);
231                         APPEND_DEVICE_INFO(device_id, "Profile", CL_DEVICE_PROFILE, cl_string);
232                         APPEND_DEVICE_INFO(device_id, "Version", CL_DEVICE_VERSION, cl_string);
233                         APPEND_DEVICE_INFO(device_id, "Extensions", CL_DEVICE_EXTENSIONS, cl_string);
234                         APPEND_DEVICE_INFO(device_id, "Max clock frequency (MHz)", CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint);
235                         APPEND_DEVICE_INFO(device_id, "Max compute units", CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint);
236                         APPEND_DEVICE_INFO(device_id, "Max work group size", CL_DEVICE_MAX_WORK_GROUP_SIZE, size_t);
237                 }
238         }
239
240 #undef APPEND_STRING_INFO
241 #undef APPEND_PLATFORM_STRING_INFO
242 #undef APPEND_DEVICE_STRING_INFO
243
244         return result;
245 }
246
247 CCL_NAMESPACE_END
248
249 #endif /* WITH_OPENCL */