Code refactor: move more memory allocation logic into device API.
[blender-staging.git] / intern / cycles / device / device.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 #include <stdlib.h>
18 #include <string.h>
19
20 #include "device/device.h"
21 #include "device/device_intern.h"
22
23 #include "util/util_debug.h"
24 #include "util/util_foreach.h"
25 #include "util/util_half.h"
26 #include "util/util_logging.h"
27 #include "util/util_math.h"
28 #include "util/util_opengl.h"
29 #include "util/util_time.h"
30 #include "util/util_system.h"
31 #include "util/util_types.h"
32 #include "util/util_vector.h"
33 #include "util/util_string.h"
34
35 CCL_NAMESPACE_BEGIN
36
37 bool Device::need_types_update = true;
38 bool Device::need_devices_update = true;
39 thread_mutex Device::device_mutex;
40 vector<DeviceType> Device::types;
41 vector<DeviceInfo> Device::devices;
42
43 /* Device Requested Features */
44
45 std::ostream& operator <<(std::ostream &os,
46                           const DeviceRequestedFeatures& requested_features)
47 {
48         os << "Experimental features: "
49            << (requested_features.experimental ? "On" : "Off") << std::endl;
50         os << "Max closure count: " << requested_features.max_closure << std::endl;
51         os << "Max nodes group: " << requested_features.max_nodes_group << std::endl;
52         /* TODO(sergey): Decode bitflag into list of names. */
53         os << "Nodes features: " << requested_features.nodes_features << std::endl;
54         os << "Use Hair: "
55            << string_from_bool(requested_features.use_hair) << std::endl;
56         os << "Use Object Motion: "
57            << string_from_bool(requested_features.use_object_motion) << std::endl;
58         os << "Use Camera Motion: "
59            << string_from_bool(requested_features.use_camera_motion) << std::endl;
60         os << "Use Baking: "
61            << string_from_bool(requested_features.use_baking) << std::endl;
62         os << "Use Subsurface: "
63            << string_from_bool(requested_features.use_subsurface) << std::endl;
64         os << "Use Volume: "
65            << string_from_bool(requested_features.use_volume) << std::endl;
66         os << "Use Branched Integrator: "
67            << string_from_bool(requested_features.use_integrator_branched) << std::endl;
68         os << "Use Patch Evaluation: "
69            << string_from_bool(requested_features.use_patch_evaluation) << std::endl;
70         os << "Use Transparent Shadows: "
71            << string_from_bool(requested_features.use_transparent) << std::endl;
72         os << "Use Principled BSDF: "
73            << string_from_bool(requested_features.use_principled) << std::endl;
74         os << "Use Denoising: "
75            << string_from_bool(requested_features.use_denoising) << std::endl;
76         return os;
77 }
78
79 /* Device */
80
81 Device::~Device()
82 {
83         if(!background && vertex_buffer != 0) {
84                 glDeleteBuffers(1, &vertex_buffer);
85         }
86 }
87
88 void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
89         const DeviceDrawParams &draw_params)
90 {
91         assert(mem.type == MEM_PIXELS);
92
93         mem_copy_from(rgba, y, w, h, rgba.memory_elements_size(1));
94
95         if(transparent) {
96                 glEnable(GL_BLEND);
97                 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
98         }
99
100         glColor3f(1.0f, 1.0f, 1.0f);
101
102         if(rgba.data_type == TYPE_HALF) {
103                 /* for multi devices, this assumes the inefficient method that we allocate
104                  * all pixels on the device even though we only render to a subset */
105                 GLhalf *data_pointer = (GLhalf*)rgba.data_pointer;
106                 float vbuffer[16], *basep;
107                 float *vp = NULL;
108
109                 data_pointer += 4*y*w;
110
111                 /* draw half float texture, GLSL shader for display transform assumed to be bound */
112                 GLuint texid;
113                 glGenTextures(1, &texid);
114                 glBindTexture(GL_TEXTURE_2D, texid);
115                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer);
116                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
117                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
118
119                 glEnable(GL_TEXTURE_2D);
120
121                 if(draw_params.bind_display_space_shader_cb) {
122                         draw_params.bind_display_space_shader_cb();
123                 }
124
125                 if(GLEW_VERSION_1_5) {
126                         if(!vertex_buffer)
127                                 glGenBuffers(1, &vertex_buffer);
128
129                         glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
130                         /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
131                         glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
132
133                         vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
134
135                         basep = NULL;
136                 }
137                 else {
138                         basep = vbuffer;
139                         vp = vbuffer;
140                 }
141
142                 if(vp) {
143                         /* texture coordinate - vertex pair */
144                         vp[0] = 0.0f;
145                         vp[1] = 0.0f;
146                         vp[2] = dx;
147                         vp[3] = dy;
148
149                         vp[4] = 1.0f;
150                         vp[5] = 0.0f;
151                         vp[6] = (float)width + dx;
152                         vp[7] = dy;
153
154                         vp[8] = 1.0f;
155                         vp[9] = 1.0f;
156                         vp[10] = (float)width + dx;
157                         vp[11] = (float)height + dy;
158
159                         vp[12] = 0.0f;
160                         vp[13] = 1.0f;
161                         vp[14] = dx;
162                         vp[15] = (float)height + dy;
163
164                         if(vertex_buffer)
165                                 glUnmapBuffer(GL_ARRAY_BUFFER);
166                 }
167
168                 glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep);
169                 glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float));
170
171                 glEnableClientState(GL_VERTEX_ARRAY);
172                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
173
174                 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
175
176                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
177                 glDisableClientState(GL_VERTEX_ARRAY);
178
179                 if(vertex_buffer) {
180                         glBindBuffer(GL_ARRAY_BUFFER, 0);
181                 }
182
183                 if(draw_params.unbind_display_space_shader_cb) {
184                         draw_params.unbind_display_space_shader_cb();
185                 }
186
187                 glBindTexture(GL_TEXTURE_2D, 0);
188                 glDisable(GL_TEXTURE_2D);
189                 glDeleteTextures(1, &texid);
190         }
191         else {
192                 /* fallback for old graphics cards that don't support GLSL, half float,
193                  * and non-power-of-two textures */
194                 glPixelZoom((float)width/(float)w, (float)height/(float)h);
195                 glRasterPos2f(dx, dy);
196
197                 uint8_t *pixels = (uint8_t*)rgba.data_pointer;
198
199                 pixels += 4*y*w;
200
201                 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
202
203                 glRasterPos2f(0.0f, 0.0f);
204                 glPixelZoom(1.0f, 1.0f);
205         }
206
207         if(transparent)
208                 glDisable(GL_BLEND);
209 }
210
211 Device *Device::create(DeviceInfo& info, Stats &stats, bool background)
212 {
213         Device *device;
214
215         switch(info.type) {
216                 case DEVICE_CPU:
217                         device = device_cpu_create(info, stats, background);
218                         break;
219 #ifdef WITH_CUDA
220                 case DEVICE_CUDA:
221                         if(device_cuda_init())
222                                 device = device_cuda_create(info, stats, background);
223                         else
224                                 device = NULL;
225                         break;
226 #endif
227 #ifdef WITH_MULTI
228                 case DEVICE_MULTI:
229                         device = device_multi_create(info, stats, background);
230                         break;
231 #endif
232 #ifdef WITH_NETWORK
233                 case DEVICE_NETWORK:
234                         device = device_network_create(info, stats, "127.0.0.1");
235                         break;
236 #endif
237 #ifdef WITH_OPENCL
238                 case DEVICE_OPENCL:
239                         if(device_opencl_init())
240                                 device = device_opencl_create(info, stats, background);
241                         else
242                                 device = NULL;
243                         break;
244 #endif
245                 default:
246                         return NULL;
247         }
248
249         return device;
250 }
251
252 DeviceType Device::type_from_string(const char *name)
253 {
254         if(strcmp(name, "CPU") == 0)
255                 return DEVICE_CPU;
256         else if(strcmp(name, "CUDA") == 0)
257                 return DEVICE_CUDA;
258         else if(strcmp(name, "OPENCL") == 0)
259                 return DEVICE_OPENCL;
260         else if(strcmp(name, "NETWORK") == 0)
261                 return DEVICE_NETWORK;
262         else if(strcmp(name, "MULTI") == 0)
263                 return DEVICE_MULTI;
264
265         return DEVICE_NONE;
266 }
267
268 string Device::string_from_type(DeviceType type)
269 {
270         if(type == DEVICE_CPU)
271                 return "CPU";
272         else if(type == DEVICE_CUDA)
273                 return "CUDA";
274         else if(type == DEVICE_OPENCL)
275                 return "OPENCL";
276         else if(type == DEVICE_NETWORK)
277                 return "NETWORK";
278         else if(type == DEVICE_MULTI)
279                 return "MULTI";
280
281         return "";
282 }
283
284 vector<DeviceType>& Device::available_types()
285 {
286         thread_scoped_lock lock(device_mutex);
287         if(need_types_update) {
288                 types.clear();
289                 types.push_back(DEVICE_CPU);
290 #ifdef WITH_CUDA
291                 if(device_cuda_init()) {
292                         types.push_back(DEVICE_CUDA);
293                 }
294 #endif
295 #ifdef WITH_OPENCL
296                 if(device_opencl_init()) {
297                         types.push_back(DEVICE_OPENCL);
298                 }
299 #endif
300 #ifdef WITH_NETWORK
301                 types.push_back(DEVICE_NETWORK);
302 #endif
303                 need_types_update = false;
304         }
305         return types;
306 }
307
308 vector<DeviceInfo>& Device::available_devices()
309 {
310         thread_scoped_lock lock(device_mutex);
311         if(need_devices_update) {
312                 devices.clear();
313 #ifdef WITH_OPENCL
314                 if(device_opencl_init()) {
315                         device_opencl_info(devices);
316                 }
317 #endif
318 #ifdef WITH_CUDA
319                 if(device_cuda_init()) {
320                         device_cuda_info(devices);
321                 }
322 #endif
323                 device_cpu_info(devices);
324 #ifdef WITH_NETWORK
325                 device_network_info(devices);
326 #endif
327                 need_devices_update = false;
328         }
329         return devices;
330 }
331
332 string Device::device_capabilities()
333 {
334         string capabilities = "CPU device capabilities: ";
335         capabilities += device_cpu_capabilities() + "\n";
336
337 #ifdef WITH_OPENCL
338         if(device_opencl_init()) {
339                 capabilities += "\nOpenCL device capabilities:\n";
340                 capabilities += device_opencl_capabilities();
341         }
342 #endif
343
344 #ifdef WITH_CUDA
345         if(device_cuda_init()) {
346                 capabilities += "\nCUDA device capabilities:\n";
347                 capabilities += device_cuda_capabilities();
348         }
349 #endif
350
351         return capabilities;
352 }
353
354 DeviceInfo Device::get_multi_device(const vector<DeviceInfo>& subdevices, int threads, bool background)
355 {
356         assert(subdevices.size() > 1);
357
358         DeviceInfo info;
359         info.type = DEVICE_MULTI;
360         info.id = "MULTI";
361         info.description = "Multi Device";
362         info.num = 0;
363
364         info.has_bindless_textures = true;
365         info.has_volume_decoupled = true;
366         info.has_qbvh = true;
367         info.has_osl = true;
368
369         foreach(const DeviceInfo &device, subdevices) {
370                 info.has_bindless_textures &= device.has_bindless_textures;
371                 info.has_volume_decoupled &= device.has_volume_decoupled;
372                 info.has_qbvh &= device.has_qbvh;
373                 info.has_osl &= device.has_osl;
374
375                 if(device.type == DEVICE_CPU && subdevices.size() > 1) {
376                         if(background) {
377                                 int orig_cpu_threads = (threads)? threads: system_cpu_thread_count();
378                                 int cpu_threads = max(orig_cpu_threads - (subdevices.size() - 1), 0);
379
380                                 if(cpu_threads >= 1) {
381                                         DeviceInfo cpu_device = device;
382                                         cpu_device.cpu_threads = cpu_threads;
383                                         info.multi_devices.push_back(cpu_device);
384                                 }
385
386                                 VLOG(1) << "CPU render threads reduced from "
387                                                 << orig_cpu_threads << " to " << cpu_threads
388                                                 << ", to dedicate to GPU.";
389                         }
390                         else {
391                                 VLOG(1) << "CPU render threads disabled for interactive render.";
392                         }
393                 }
394                 else {
395                         info.multi_devices.push_back(device);
396                 }
397         }
398
399         return info;
400 }
401
402 void Device::tag_update()
403 {
404         need_types_update = true;
405         need_devices_update = true;
406 }
407
408 void Device::free_memory()
409 {
410         need_types_update = true;
411         need_devices_update = true;
412         types.free_memory();
413         devices.free_memory();
414 }
415
416 CCL_NAMESPACE_END