Fix related to #32929: update list of available devices for cycles rendering
[blender.git] / intern / cycles / device / device.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "device.h"
23 #include "device_intern.h"
24
25 #include "util_cuda.h"
26 #include "util_debug.h"
27 #include "util_foreach.h"
28 #include "util_math.h"
29 #include "util_opencl.h"
30 #include "util_opengl.h"
31 #include "util_time.h"
32 #include "util_types.h"
33 #include "util_vector.h"
34
35 CCL_NAMESPACE_BEGIN
36
37 /* Device */
38
39 void Device::pixels_alloc(device_memory& mem)
40 {
41         mem_alloc(mem, MEM_READ_WRITE);
42 }
43
44 void Device::pixels_copy_from(device_memory& mem, int y, int w, int h)
45 {
46         mem_copy_from(mem, y, w, h, sizeof(uint8_t)*4);
47 }
48
49 void Device::pixels_free(device_memory& mem)
50 {
51         mem_free(mem);
52 }
53
54 void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int width, int height, bool transparent)
55 {
56         pixels_copy_from(rgba, y, w, h);
57
58         if(transparent) {
59                 glEnable(GL_BLEND);
60                 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
61         }
62
63         glPixelZoom((float)width/(float)w, (float)height/(float)h);
64         glRasterPos2f(0, dy);
65
66         uint8_t *pixels = (uint8_t*)rgba.data_pointer;
67
68         /* for multi devices, this assumes the ineffecient method that we allocate
69          * all pixels on the device even though we only render to a subset */
70         pixels += 4*y*w;
71
72         glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
73
74         glRasterPos2f(0.0f, 0.0f);
75         glPixelZoom(1.0f, 1.0f);
76
77         if(transparent)
78                 glDisable(GL_BLEND);
79 }
80
81 Device *Device::create(DeviceInfo& info, bool background, int threads)
82 {
83         Device *device;
84
85         switch(info.type) {
86                 case DEVICE_CPU:
87                         device = device_cpu_create(info, threads);
88                         break;
89 #ifdef WITH_CUDA
90                 case DEVICE_CUDA:
91                         if(cuLibraryInit())
92                                 device = device_cuda_create(info, background);
93                         else
94                                 device = NULL;
95                         break;
96 #endif
97 #ifdef WITH_MULTI
98                 case DEVICE_MULTI:
99                         device = device_multi_create(info, background);
100                         break;
101 #endif
102 #ifdef WITH_NETWORK
103                 case DEVICE_NETWORK:
104                         device = device_network_create(info, "127.0.0.1");
105                         break;
106 #endif
107 #ifdef WITH_OPENCL
108                 case DEVICE_OPENCL:
109                         if(clLibraryInit())
110                                 device = device_opencl_create(info, background);
111                         else
112                                 device = NULL;
113                         break;
114 #endif
115                 default:
116                         return NULL;
117         }
118
119         if(device)
120                 device->info = info;
121
122         return device;
123 }
124
125 DeviceType Device::type_from_string(const char *name)
126 {
127         if(strcmp(name, "cpu") == 0)
128                 return DEVICE_CPU;
129         else if(strcmp(name, "cuda") == 0)
130                 return DEVICE_CUDA;
131         else if(strcmp(name, "opencl") == 0)
132                 return DEVICE_OPENCL;
133         else if(strcmp(name, "network") == 0)
134                 return DEVICE_NETWORK;
135         else if(strcmp(name, "multi") == 0)
136                 return DEVICE_MULTI;
137         
138         return DEVICE_NONE;
139 }
140
141 string Device::string_from_type(DeviceType type)
142 {
143         if(type == DEVICE_CPU)
144                 return "cpu";
145         else if(type == DEVICE_CUDA)
146                 return "cuda";
147         else if(type == DEVICE_OPENCL)
148                 return "opencl";
149         else if(type == DEVICE_NETWORK)
150                 return "network";
151         else if(type == DEVICE_MULTI)
152                 return "multi";
153         
154         return "";
155 }
156
157 vector<DeviceType>& Device::available_types()
158 {
159         static vector<DeviceType> types;
160         static bool types_init = false;
161
162         if(!types_init) {
163                 types.push_back(DEVICE_CPU);
164
165 #ifdef WITH_CUDA
166                 if(cuLibraryInit())
167                         types.push_back(DEVICE_CUDA);
168 #endif
169
170 #ifdef WITH_OPENCL
171                 if(clLibraryInit())
172                         types.push_back(DEVICE_OPENCL);
173 #endif
174
175 #ifdef WITH_NETWORK
176                 types.push_back(DEVICE_NETWORK);
177 #endif
178 #ifdef WITH_MULTI
179                 types.push_back(DEVICE_MULTI);
180 #endif
181
182                 types_init = true;
183         }
184
185         return types;
186 }
187
188 vector<DeviceInfo>& Device::available_devices()
189 {
190         static vector<DeviceInfo> devices;
191         static bool devices_init = false;
192         static double device_update_time = 0.0;
193
194         /* only update device list if we're not actively rendering already, things
195          * could go very wrong if a device suddenly becomes (un)available. also do
196          * it only every 5 seconds. it not super cpu intensive but don't want to do
197          * it on every redraw. */
198         if(devices_init) {
199                 if(!TaskScheduler::active() && (time_dt() > device_update_time + 5.0)) {
200                         devices.clear();
201                         devices_init = false;
202                 }
203         }
204
205         if(!devices_init) {
206 #ifdef WITH_CUDA
207                 if(cuLibraryInit())
208                         device_cuda_info(devices);
209 #endif
210
211 #ifdef WITH_OPENCL
212                 if(clLibraryInit())
213                         device_opencl_info(devices);
214 #endif
215
216 #ifdef WITH_MULTI
217                 device_multi_info(devices);
218 #endif
219
220                 device_cpu_info(devices);
221
222 #ifdef WITH_NETWORK
223                 device_network_info(devices);
224 #endif
225
226                 devices_init = true;
227                 device_update_time = time_dt();
228         }
229
230         return devices;
231 }
232
233 CCL_NAMESPACE_END
234