Blender V5.0
device/hip/device.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "device/hip/device.h"
6#include "device/device.h"
7
8#include "util/log.h"
9
10#ifdef WITH_HIP
12
13# include "integrator/denoiser_oidn_gpu.h" // IWYU pragma: keep
14
15# include "util/string.h"
16# ifdef _WIN32
17# include "util/windows.h"
18# endif
19#endif /* WITH_HIP */
20
21#ifdef WITH_HIPRT
23#endif
24
26
28{
29#if !defined(WITH_HIP)
30 return false;
31#elif defined(WITH_HIP_DYNLOAD)
32 static bool initialized = false;
33 static bool result = false;
34
35 if (initialized) {
36 return result;
37 }
38
39 initialized = true;
40 int hipew_result = hipewInit(HIPEW_INIT_HIP);
41
42 if (hipew_result == HIPEW_SUCCESS) {
43 LOG_INFO << "HIPEW initialization succeeded";
44 if (!hipSupportsDriver()) {
45 LOG_WARNING << "Driver version is too old";
46 }
47 else if (HIPDevice::have_precompiled_kernels()) {
48 LOG_INFO << "Found precompiled kernels";
49 result = true;
50 }
51 else if (hipewCompilerPath() != nullptr) {
52 LOG_INFO << "Found HIPCC " << hipewCompilerPath();
53 result = true;
54 }
55 else {
56 LOG_INFO << "Neither precompiled kernels nor HIPCC was found,"
57 << " unable to use HIP";
58 }
59 }
60 else {
61 if (hipew_result == HIPEW_ERROR_ATEXIT_FAILED) {
62 LOG_WARNING << "HIPEW initialization failed: Error setting up atexit() handler";
63 }
64 else if (hipew_result == HIPEW_ERROR_OLD_DRIVER) {
65 LOG_WARNING << "HIPEW initialization failed: Driver version too old, requires AMD Adrenalin "
66 "driver 24.9.1 or newer, or AMD Radeon Pro driver 24.Q4 or newer";
67 }
68 else {
69 LOG_WARNING << "HIPEW initialization failed: Error opening HIP dynamic library";
70 }
71 }
72
73 return result;
74#else /* WITH_HIP_DYNLOAD */
75 return true;
76#endif /* WITH_HIP_DYNLOAD */
77}
78
80 Stats &stats,
81 Profiler &profiler,
82 const bool headless)
83{
84#ifdef WITH_HIPRT
85 if (info.use_hardware_raytracing) {
86 return make_unique<HIPRTDevice>(info, stats, profiler, headless);
87 }
88 return make_unique<HIPDevice>(info, stats, profiler, headless);
89#elif defined(WITH_HIP)
90 return make_unique<HIPDevice>(info, stats, profiler, headless);
91#else
92 (void)info;
93 (void)stats;
94 (void)profiler;
95 (void)headless;
96
97 LOG_FATAL << "Request to create HIP device without compiled-in support. Should never happen.";
98
99 return nullptr;
100#endif
101}
102
103#ifdef WITH_HIP
104static hipError_t device_hip_safe_init()
105{
106# ifdef _WIN32
107 __try
108 {
109 return hipInit(0);
110 }
111 __except (EXCEPTION_EXECUTE_HANDLER)
112 {
113 /* Ignore crashes inside the HIP driver and hope we can
114 * survive even with corrupted HIP installs. */
115 fprintf(stderr, "Cycles HIP: driver crashed, continuing without HIP.\n");
116 }
117
118 return hipErrorNoDevice;
119# else
120 return hipInit(0);
121# endif
122}
123#endif /* WITH_HIP */
124
126{
127#ifdef WITH_HIP
128 hipError_t result = device_hip_safe_init();
129 if (result != hipSuccess) {
130 if (result != hipErrorNoDevice) {
131 LOG_ERROR << "HIP hipInit: " << hipewErrorString(result);
132 }
133 return;
134 }
135
136 int count = 0;
137 result = hipGetDeviceCount(&count);
138 if (result != hipSuccess) {
139 LOG_ERROR << "HIP hipGetDeviceCount: " << hipewErrorString(result);
140 return;
141 }
142
143# ifdef WITH_HIPRT
144 const bool has_hardware_raytracing = hiprtewInit();
145# else
146 const bool has_hardware_raytracing = false;
147# endif
148
149 vector<DeviceInfo> display_devices;
150
151 for (int num = 0; num < count; num++) {
152 char name[256];
153
154 result = hipDeviceGetName(name, 256, num);
155 if (result != hipSuccess) {
156 LOG_ERROR << "HIP hipDeviceGetName: " << hipewErrorString(result);
157 continue;
158 }
159
160 if (!hipSupportsDevice(num)) {
161 continue;
162 }
163
164 DeviceInfo info;
165
166 info.type = DEVICE_HIP;
167 info.description = string(name);
168 info.num = num;
169
170 info.has_mnee = true;
171 info.has_nanovdb = true;
172
173 info.has_gpu_queue = true;
174 /* Check if the device has P2P access to any other device in the system. */
175 for (int peer_num = 0; peer_num < count && !info.has_peer_memory; peer_num++) {
176 if (num != peer_num) {
177 if (hipSupportsDevice(peer_num)) {
178 int can_access = 0;
179 hipDeviceCanAccessPeer(&can_access, num, peer_num);
180 info.has_peer_memory = (can_access != 0);
181 }
182 }
183 }
184
185 /* Disable on RDNA1 due to bug rendering curves in HIP-RT 2.5 or HIP SDK 6.3. */
186 info.use_hardware_raytracing = has_hardware_raytracing && hipIsRDNA2OrNewer(num);
187
188 int pci_location[3] = {0, 0, 0};
189 hipDeviceGetAttribute(&pci_location[0], hipDeviceAttributePciDomainID, num);
190 hipDeviceGetAttribute(&pci_location[1], hipDeviceAttributePciBusId, num);
191 hipDeviceGetAttribute(&pci_location[2], hipDeviceAttributePciDeviceId, num);
192 info.id = string_printf("HIP_%s_%04x:%02x:%02x",
193 name,
194 (unsigned int)pci_location[0],
195 (unsigned int)pci_location[1],
196 (unsigned int)pci_location[2]);
197
198 info.denoisers = 0;
199# if defined(WITH_OPENIMAGEDENOISE)
200 /* Check first if OIDN supports it, not doing so can crash the HIP driver with
201 * "hipErrorNoBinaryForGpu: Unable to find code object for all current devices". */
202# if OIDN_VERSION >= 20300
203 if (hipSupportsDeviceOIDN(num) && oidnIsHIPDeviceSupported(num)) {
204# else
205 if (hipSupportsDeviceOIDN(num) && OIDNDenoiserGPU::is_device_supported(info)) {
206# endif
208 }
209# endif
210
211 /* If device has a kernel timeout and no compute preemption, we assume
212 * it is connected to a display and will freeze the display while doing
213 * computations. */
214 int timeout_attr = 0;
215 hipDeviceGetAttribute(&timeout_attr, hipDeviceAttributeKernelExecTimeout, num);
216
217 if (timeout_attr) {
218 LOG_INFO << "Device is recognized as display.";
219 info.description += " (Display)";
220 info.display_device = true;
221 display_devices.push_back(info);
222 }
223 else {
224 LOG_INFO << "Device has compute preemption or is not used for display.";
225 devices.push_back(info);
226 }
227
228 LOG_INFO << "Added device \"" << info.description << "\" with id \"" << info.id << "\".";
229
231 LOG_INFO << "Device with id \"" << info.id << "\" supports "
233 }
234 }
235
236 if (!display_devices.empty()) {
237 devices.insert(devices.end(), display_devices.begin(), display_devices.end());
238 }
239#else /* WITH_HIP */
240 (void)devices;
241#endif /* WITH_HIP */
242}
243
245{
246#ifdef WITH_HIP
247 hipError_t result = device_hip_safe_init();
248 if (result != hipSuccess) {
249 if (result != hipErrorNoDevice) {
250 return string("Error initializing HIP: ") + hipewErrorString(result);
251 }
252 return "No HIP device found\n";
253 }
254
255 int count;
256 result = hipGetDeviceCount(&count);
257 if (result != hipSuccess) {
258 return string("Error getting devices: ") + hipewErrorString(result);
259 }
260
261 string capabilities;
262 for (int num = 0; num < count; num++) {
263 char name[256];
264 if (hipDeviceGetName(name, 256, num) != hipSuccess) {
265 continue;
266 }
267 capabilities += string("\t") + name + "\n";
268 int value;
269# define GET_ATTR(attr) \
270 { \
271 if (hipDeviceGetAttribute(&value, hipDeviceAttribute##attr, num) == hipSuccess) { \
272 capabilities += string_printf("\t\thipDeviceAttribute" #attr "\t\t\t%d\n", value); \
273 } \
274 } \
275 (void)0
276 /* TODO(sergey): Strip all attributes which are not useful for us
277 * or does not depend on the driver.
278 */
279 GET_ATTR(MaxThreadsPerBlock);
280 GET_ATTR(MaxBlockDimX);
281 GET_ATTR(MaxBlockDimY);
282 GET_ATTR(MaxBlockDimZ);
283 GET_ATTR(MaxGridDimX);
284 GET_ATTR(MaxGridDimY);
285 GET_ATTR(MaxGridDimZ);
286 GET_ATTR(MaxSharedMemoryPerBlock);
287 GET_ATTR(TotalConstantMemory);
288 GET_ATTR(WarpSize);
289 GET_ATTR(MaxPitch);
290 GET_ATTR(MaxRegistersPerBlock);
291 GET_ATTR(ClockRate);
292 GET_ATTR(TextureAlignment);
293 GET_ATTR(MultiprocessorCount);
294 GET_ATTR(KernelExecTimeout);
295 GET_ATTR(Integrated);
296 GET_ATTR(CanMapHostMemory);
297 GET_ATTR(ComputeMode);
298 GET_ATTR(MaxTexture1DWidth);
299 GET_ATTR(MaxTexture2DWidth);
300 GET_ATTR(MaxTexture2DHeight);
301 GET_ATTR(MaxTexture3DWidth);
302 GET_ATTR(MaxTexture3DHeight);
303 GET_ATTR(MaxTexture3DDepth);
304 GET_ATTR(ConcurrentKernels);
305 GET_ATTR(EccEnabled);
306 GET_ATTR(MemoryClockRate);
307 GET_ATTR(MemoryBusWidth);
308 GET_ATTR(L2CacheSize);
309 GET_ATTR(MaxThreadsPerMultiProcessor);
310 GET_ATTR(ComputeCapabilityMajor);
311 GET_ATTR(ComputeCapabilityMinor);
312 GET_ATTR(MaxSharedMemoryPerMultiprocessor);
313 GET_ATTR(ManagedMemory);
314 GET_ATTR(IsMultiGpuBoard);
315# undef GET_ATTR
316 capabilities += "\n";
317 }
318
319 return capabilities;
320
321#else /* WITH_HIP */
322 return "";
323#endif /* WITH_HIP */
324}
325
ATTR_WARN_UNUSED_RESULT const size_t num
DenoiserTypeMask denoisers
bool display_device
bool has_peer_memory
bool has_gpu_queue
DeviceType type
string description
bool use_hardware_raytracing
CCL_NAMESPACE_BEGIN const char * denoiserTypeToHumanReadable(DenoiserType type)
Definition denoise.cpp:9
@ DENOISER_OPENIMAGEDENOISE
Definition denoise.h:13
#define CCL_NAMESPACE_END
@ DEVICE_HIP
void device_hip_info(vector< DeviceInfo > &devices)
string device_hip_capabilities()
unique_ptr< Device > device_hip_create(const DeviceInfo &info, Stats &stats, Profiler &profiler, const bool headless)
CCL_NAMESPACE_BEGIN bool device_hip_init()
static bool initialized
int count
#define LOG_FATAL
Definition log.h:99
#define LOG_ERROR
Definition log.h:101
#define LOG_WARNING
Definition log.h:103
#define LOG_INFO
Definition log.h:106
const char * name
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23