Fix #118709: Crash in OIDN GPU detection for unsupported HIP device
[blender.git] / intern / cycles / device / hip / device.cpp
blob62730e06b062a1285b06eb12ad4d89438a59a0f0
1 /* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 * SPDX-License-Identifier: Apache-2.0 */
5 #include "device/hip/device.h"
7 #include "util/log.h"
9 #ifdef WITH_HIP
10 # include "device/device.h"
11 # include "device/hip/device_impl.h"
13 # include "integrator/denoiser_oidn_gpu.h"
15 # include "util/string.h"
16 # include "util/windows.h"
17 #endif /* WITH_HIP */
19 #ifdef WITH_HIPRT
20 # include "device/hiprt/device_impl.h"
21 #endif
23 CCL_NAMESPACE_BEGIN
25 bool device_hip_init()
27 #if !defined(WITH_HIP)
28 return false;
29 #elif defined(WITH_HIP_DYNLOAD)
30 static bool initialized = false;
31 static bool result = false;
33 if (initialized)
34 return result;
36 initialized = true;
37 int hipew_result = hipewInit(HIPEW_INIT_HIP);
38 if (hipew_result == HIPEW_SUCCESS) {
39 VLOG_INFO << "HIPEW initialization succeeded";
40 if (HIPDevice::have_precompiled_kernels()) {
41 VLOG_INFO << "Found precompiled kernels";
42 result = true;
44 else if (hipewCompilerPath() != NULL) {
45 VLOG_INFO << "Found HIPCC " << hipewCompilerPath();
46 result = true;
48 else {
49 VLOG_INFO << "Neither precompiled kernels nor HIPCC was found,"
50 << " unable to use HIP";
53 else {
54 if (hipew_result == HIPEW_ERROR_ATEXIT_FAILED) {
55 VLOG_WARNING << "HIPEW initialization failed: Error setting up atexit() handler";
57 else if (hipew_result == HIPEW_ERROR_OLD_DRIVER) {
58 VLOG_WARNING
59 << "HIPEW initialization failed: Driver version too old, requires AMD Radeon Pro "
60 "21.Q4 driver or newer";
62 else {
63 VLOG_WARNING << "HIPEW initialization failed: Error opening HIP dynamic library";
67 return result;
68 #else /* WITH_HIP_DYNLOAD */
69 return true;
70 #endif /* WITH_HIP_DYNLOAD */
73 Device *device_hip_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
75 #ifdef WITH_HIPRT
76 if (info.use_hardware_raytracing)
77 return new HIPRTDevice(info, stats, profiler);
78 else
79 return new HIPDevice(info, stats, profiler);
80 #elif defined(WITH_HIP)
81 return new HIPDevice(info, stats, profiler);
82 #else
83 (void)info;
84 (void)stats;
85 (void)profiler;
87 LOG(FATAL) << "Request to create HIP device without compiled-in support. Should never happen.";
89 return nullptr;
90 #endif
93 #ifdef WITH_HIP
94 static hipError_t device_hip_safe_init()
96 # ifdef _WIN32
97 __try
99 return hipInit(0);
101 __except (EXCEPTION_EXECUTE_HANDLER)
103 /* Ignore crashes inside the HIP driver and hope we can
104 * survive even with corrupted HIP installs. */
105 fprintf(stderr, "Cycles HIP: driver crashed, continuing without HIP.\n");
108 return hipErrorNoDevice;
109 # else
110 return hipInit(0);
111 # endif
113 #endif /* WITH_HIP */
115 void device_hip_info(vector<DeviceInfo> &devices)
117 #ifdef WITH_HIP
118 hipError_t result = device_hip_safe_init();
119 if (result != hipSuccess) {
120 if (result != hipErrorNoDevice)
121 fprintf(stderr, "HIP hipInit: %s\n", hipewErrorString(result));
122 return;
125 int count = 0;
126 result = hipGetDeviceCount(&count);
127 if (result != hipSuccess) {
128 fprintf(stderr, "HIP hipGetDeviceCount: %s\n", hipewErrorString(result));
129 return;
132 # ifdef WITH_HIPRT
133 const bool has_hardware_raytracing = hiprtewInit();
134 # else
135 const bool has_hardware_raytracing = false;
136 # endif
138 vector<DeviceInfo> display_devices;
140 for (int num = 0; num < count; num++) {
141 char name[256];
143 result = hipDeviceGetName(name, 256, num);
144 if (result != hipSuccess) {
145 fprintf(stderr, "HIP :hipDeviceGetName: %s\n", hipewErrorString(result));
146 continue;
149 if (!hipSupportsDevice(num)) {
150 continue;
153 DeviceInfo info;
155 info.type = DEVICE_HIP;
156 info.description = string(name);
157 info.num = num;
159 info.has_nanovdb = true;
160 info.has_light_tree = true;
161 info.has_mnee = true;
163 info.has_gpu_queue = true;
164 /* Check if the device has P2P access to any other device in the system. */
165 for (int peer_num = 0; peer_num < count && !info.has_peer_memory; peer_num++) {
166 if (num != peer_num) {
167 int can_access = 0;
168 hipDeviceCanAccessPeer(&can_access, num, peer_num);
169 info.has_peer_memory = (can_access != 0);
173 info.use_hardware_raytracing = has_hardware_raytracing;
175 int pci_location[3] = {0, 0, 0};
176 hipDeviceGetAttribute(&pci_location[0], hipDeviceAttributePciDomainID, num);
177 hipDeviceGetAttribute(&pci_location[1], hipDeviceAttributePciBusId, num);
178 hipDeviceGetAttribute(&pci_location[2], hipDeviceAttributePciDeviceId, num);
179 info.id = string_printf("HIP_%s_%04x:%02x:%02x",
180 name,
181 (unsigned int)pci_location[0],
182 (unsigned int)pci_location[1],
183 (unsigned int)pci_location[2]);
185 info.denoisers = 0;
186 # if defined(WITH_OPENIMAGEDENOISE)
187 /* Check first if OIDN supports it, not doing so can crash the HIP driver with
188 * "hipErrorNoBinaryForGpu: Unable to find code object for all current devices". */
189 if (hipSupportsDeviceOIDN(num) && OIDNDenoiserGPU::is_device_supported(info)) {
190 info.denoisers |= DENOISER_OPENIMAGEDENOISE;
192 # endif
194 /* If device has a kernel timeout and no compute preemption, we assume
195 * it is connected to a display and will freeze the display while doing
196 * computations. */
197 int timeout_attr = 0;
198 hipDeviceGetAttribute(&timeout_attr, hipDeviceAttributeKernelExecTimeout, num);
200 if (timeout_attr) {
201 VLOG_INFO << "Device is recognized as display.";
202 info.description += " (Display)";
203 info.display_device = true;
204 display_devices.push_back(info);
206 else {
207 VLOG_INFO << "Device has compute preemption or is not used for display.";
208 devices.push_back(info);
211 VLOG_INFO << "Added device \"" << info.description << "\" with id \"" << info.id << "\".";
213 if (info.denoisers & DENOISER_OPENIMAGEDENOISE)
214 VLOG_INFO << "Device with id \"" << info.id << "\" is supporting "
215 << denoiserTypeToHumanReadable(DENOISER_OPENIMAGEDENOISE) << ".";
218 if (!display_devices.empty())
219 devices.insert(devices.end(), display_devices.begin(), display_devices.end());
220 #else /* WITH_HIP */
221 (void)devices;
222 #endif /* WITH_HIP */
225 string device_hip_capabilities()
227 #ifdef WITH_HIP
228 hipError_t result = device_hip_safe_init();
229 if (result != hipSuccess) {
230 if (result != hipErrorNoDevice) {
231 return string("Error initializing HIP: ") + hipewErrorString(result);
233 return "No HIP device found\n";
236 int count;
237 result = hipGetDeviceCount(&count);
238 if (result != hipSuccess) {
239 return string("Error getting devices: ") + hipewErrorString(result);
242 string capabilities = "";
243 for (int num = 0; num < count; num++) {
244 char name[256];
245 if (hipDeviceGetName(name, 256, num) != hipSuccess) {
246 continue;
248 capabilities += string("\t") + name + "\n";
249 int value;
250 # define GET_ATTR(attr) \
252 if (hipDeviceGetAttribute(&value, hipDeviceAttribute##attr, num) == hipSuccess) { \
253 capabilities += string_printf("\t\thipDeviceAttribute" #attr "\t\t\t%d\n", value); \
256 (void)0
257 /* TODO(sergey): Strip all attributes which are not useful for us
258 * or does not depend on the driver.
260 GET_ATTR(MaxThreadsPerBlock);
261 GET_ATTR(MaxBlockDimX);
262 GET_ATTR(MaxBlockDimY);
263 GET_ATTR(MaxBlockDimZ);
264 GET_ATTR(MaxGridDimX);
265 GET_ATTR(MaxGridDimY);
266 GET_ATTR(MaxGridDimZ);
267 GET_ATTR(MaxSharedMemoryPerBlock);
268 GET_ATTR(TotalConstantMemory);
269 GET_ATTR(WarpSize);
270 GET_ATTR(MaxPitch);
271 GET_ATTR(MaxRegistersPerBlock);
272 GET_ATTR(ClockRate);
273 GET_ATTR(TextureAlignment);
274 GET_ATTR(MultiprocessorCount);
275 GET_ATTR(KernelExecTimeout);
276 GET_ATTR(Integrated);
277 GET_ATTR(CanMapHostMemory);
278 GET_ATTR(ComputeMode);
279 GET_ATTR(MaxTexture1DWidth);
280 GET_ATTR(MaxTexture2DWidth);
281 GET_ATTR(MaxTexture2DHeight);
282 GET_ATTR(MaxTexture3DWidth);
283 GET_ATTR(MaxTexture3DHeight);
284 GET_ATTR(MaxTexture3DDepth);
285 GET_ATTR(ConcurrentKernels);
286 GET_ATTR(EccEnabled);
287 GET_ATTR(MemoryClockRate);
288 GET_ATTR(MemoryBusWidth);
289 GET_ATTR(L2CacheSize);
290 GET_ATTR(MaxThreadsPerMultiProcessor);
291 GET_ATTR(ComputeCapabilityMajor);
292 GET_ATTR(ComputeCapabilityMinor);
293 GET_ATTR(MaxSharedMemoryPerMultiprocessor);
294 GET_ATTR(ManagedMemory);
295 GET_ATTR(IsMultiGpuBoard);
296 # undef GET_ATTR
297 capabilities += "\n";
300 return capabilities;
302 #else /* WITH_HIP */
303 return "";
304 #endif /* WITH_HIP */
307 CCL_NAMESPACE_END