code cleanup: quiet warnings for gcc's -Wundef, -Wmissing-declarations
[blender.git] / source / blender / compositor / intern / COM_WorkScheduler.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  * Contributor: 
19  *              Jeroen Bakker 
20  *              Monique Dewanchand
21  */
22
23 #include <list>
24 #include <stdio.h>
25
26 #include "BKE_global.h"
27
28 #include "COM_compositor.h"
29 #include "COM_WorkScheduler.h"
30 #include "COM_CPUDevice.h"
31 #include "COM_OpenCLDevice.h"
32 #include "COM_OpenCLKernels.cl.h"
33 #include "OCL_opencl.h"
34 #include "COM_WriteBufferOperation.h"
35
36 #include "MEM_guardedalloc.h"
37
38 #include "PIL_time.h"
39 #include "BLI_threads.h"
40
41 #if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD
42 #  ifndef DEBUG  /* test this so we dont get warnings in debug builds */
43 #    warning COM_CURRENT_THREADING_MODEL COM_TM_NOTHREAD is activated. Use only for debugging.
44 #  endif
45 #elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
46    /* do nothing - default */
47 #else
48 #  error COM_CURRENT_THREADING_MODEL No threading model selected
49 #endif
50
51
52 /// @brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
53 static vector<CPUDevice *> g_cpudevices;
54
55 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
56 /// @brief list of all thread for every CPUDevice in cpudevices a thread exists
57 static ListBase g_cputhreads;
58 static bool g_cpuInitialized = false;
59 /// @brief all scheduled work for the cpu
60 static ThreadQueue *g_cpuqueue;
61 static ThreadQueue *g_gpuqueue;
62 #ifdef COM_OPENCL_ENABLED
63 static cl_context g_context;
64 static cl_program g_program;
65 /// @brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is created
66 static vector<OpenCLDevice *> g_gpudevices;
67 /// @brief list of all thread for every GPUDevice in cpudevices a thread exists
68 static ListBase g_gputhreads;
69 /// @brief all scheduled work for the gpu
70 #ifdef COM_OPENCL_ENABLED
71 static bool g_openclActive = false;
72 static bool g_openclInitialized = false;
73 #endif
74 #endif
75 #endif
76
77 #define MAX_HIGHLIGHT 8
78 static bool g_highlightInitialized = false;
79 extern "C" {
80 int g_highlightIndex;
81 void **g_highlightedNodes;
82 void **g_highlightedNodesRead;
83
84 #define HIGHLIGHT(wp) \
85 { \
86         ExecutionGroup *group = wp->getExecutionGroup(); \
87         if (group->isComplex()) { \
88                 NodeOperation *operation = group->getOutputNodeOperation(); \
89                 if (operation->isWriteBufferOperation()) { \
90                         WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation; \
91                         NodeOperation *complexOperation = writeOperation->getInput(); \
92                         bNode *node = complexOperation->getbNode(); \
93                         if (node) { \
94                                 if (node->original) { \
95                                         node = node->original; \
96                                 } \
97                                 if (g_highlightInitialized && g_highlightedNodes) { \
98                                         if (g_highlightIndex < MAX_HIGHLIGHT) { \
99                                                 g_highlightedNodes[g_highlightIndex++] = node; \
100                                         } \
101                                 } \
102                         } \
103                 } \
104         } \
105 }
106
107 void COM_startReadHighlights()
108 {
109         if (!g_highlightInitialized)
110         {
111                 return;
112         }
113         
114         if (g_highlightedNodesRead) 
115         {
116                 MEM_freeN(g_highlightedNodesRead);
117         }
118         
119         g_highlightedNodesRead = g_highlightedNodes;
120         g_highlightedNodes = (void **)MEM_callocN(sizeof(void *) * MAX_HIGHLIGHT, __func__);
121         g_highlightIndex = 0;
122 }
123
124 int COM_isHighlightedbNode(bNode *bnode)
125 {
126         if (!g_highlightInitialized) {
127                 return false;
128         }
129         
130         if (!g_highlightedNodesRead) {
131                 return false;
132         }
133
134         for (int i = 0; i < MAX_HIGHLIGHT; i++) {
135                 void *p = g_highlightedNodesRead[i];
136                 if (!p) return false;
137                 if (p == bnode) return true;
138         }
139         return false;
140 }
141 } // end extern "C"
142
143 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
144 void *WorkScheduler::thread_execute_cpu(void *data)
145 {
146         Device *device = (Device *)data;
147         WorkPackage *work;
148         
149         while ((work = (WorkPackage *)BLI_thread_queue_pop(g_cpuqueue))) {
150                 HIGHLIGHT(work);
151                 device->execute(work);
152                 delete work;
153         }
154         
155         return NULL;
156 }
157
158 void *WorkScheduler::thread_execute_gpu(void *data)
159 {
160         Device *device = (Device *)data;
161         WorkPackage *work;
162         
163         while ((work = (WorkPackage *)BLI_thread_queue_pop(g_gpuqueue))) {
164                 HIGHLIGHT(work);
165                 device->execute(work);
166                 delete work;
167         }
168         
169         return NULL;
170 }
171 #endif
172
173
174
175 void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber)
176 {
177         WorkPackage *package = new WorkPackage(group, chunkNumber);
178 #if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD
179         CPUDevice device;
180         device.execute(package);
181         delete package;
182 #elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
183 #ifdef COM_OPENCL_ENABLED
184         if (group->isOpenCL() && g_openclActive) {
185                 BLI_thread_queue_push(g_gpuqueue, package);
186         }
187         else {
188                 BLI_thread_queue_push(g_cpuqueue, package);
189         }
190 #else
191         BLI_thread_queue_push(cpuqueue, package);
192 #endif
193 #endif
194 }
195
196 void WorkScheduler::start(CompositorContext &context)
197 {
198 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
199         unsigned int index;
200         g_cpuqueue = BLI_thread_queue_init();
201         BLI_init_threads(&g_cputhreads, thread_execute_cpu, g_cpudevices.size());
202         for (index = 0; index < g_cpudevices.size(); index++) {
203                 Device *device = g_cpudevices[index];
204                 BLI_insert_thread(&g_cputhreads, device);
205         }
206 #ifdef COM_OPENCL_ENABLED
207         if (context.getHasActiveOpenCLDevices()) {
208                 g_gpuqueue = BLI_thread_queue_init();
209                 BLI_init_threads(&g_gputhreads, thread_execute_gpu, g_gpudevices.size());
210                 for (index = 0; index < g_gpudevices.size(); index++) {
211                         Device *device = g_gpudevices[index];
212                         BLI_insert_thread(&g_gputhreads, device);
213                 }
214                 g_openclActive = true;
215         }
216         else {
217                 g_openclActive = false;
218         }
219 #endif
220 #endif
221 }
222 void WorkScheduler::finish()
223 {
224 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
225 #ifdef COM_OPENCL_ENABLED
226         if (g_openclActive) {
227                 BLI_thread_queue_wait_finish(g_gpuqueue);
228                 BLI_thread_queue_wait_finish(g_cpuqueue);
229         }
230         else {
231                 BLI_thread_queue_wait_finish(g_cpuqueue);
232         }
233 #else
234         BLI_thread_queue_wait_finish(cpuqueue);
235 #endif
236 #endif
237 }
238 void WorkScheduler::stop()
239 {
240 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
241         BLI_thread_queue_nowait(g_cpuqueue);
242         BLI_end_threads(&g_cputhreads);
243         BLI_thread_queue_free(g_cpuqueue);
244         g_cpuqueue = NULL;
245 #ifdef COM_OPENCL_ENABLED
246         if (g_openclActive) {
247                 BLI_thread_queue_nowait(g_gpuqueue);
248                 BLI_end_threads(&g_gputhreads);
249                 BLI_thread_queue_free(g_gpuqueue);
250                 g_gpuqueue = NULL;
251         }
252 #endif
253 #endif
254 }
255
256 bool WorkScheduler::hasGPUDevices()
257 {
258 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
259 #ifdef COM_OPENCL_ENABLED
260         return g_gpudevices.size() > 0;
261 #else
262         return 0;
263 #endif
264 #else
265         return 0;
266 #endif
267 }
268
269 static void clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data)
270 {
271         printf("OPENCL error: %s\n", errinfo);
272 }
273
274 void WorkScheduler::initialize(bool use_opencl)
275 {
276         /* initialize highlighting */
277         if (!g_highlightInitialized) {
278                 if (g_highlightedNodesRead) MEM_freeN(g_highlightedNodesRead);
279                 if (g_highlightedNodes)     MEM_freeN(g_highlightedNodes);
280
281                 g_highlightedNodesRead = NULL;
282                 g_highlightedNodes = NULL;
283
284                 COM_startReadHighlights();
285
286                 g_highlightInitialized = true;
287         }
288
289 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
290         /* initialize CPU threads */
291         if (!g_cpuInitialized) {
292                 int numberOfCPUThreads = BLI_system_thread_count();
293
294                 for (int index = 0; index < numberOfCPUThreads; index++) {
295                         CPUDevice *device = new CPUDevice();
296                         device->initialize();
297                         g_cpudevices.push_back(device);
298                 }
299
300                 g_cpuInitialized = true;
301         }
302
303 #ifdef COM_OPENCL_ENABLED
304         /* deinitialize OpenCL GPU's */
305         if (use_opencl && !g_openclInitialized) {
306                 g_context = NULL;
307                 g_program = NULL;
308
309                 OCL_init(); /* this will check and skip if already initialized */
310
311                 if (clCreateContextFromType) {
312                         cl_uint numberOfPlatforms = 0;
313                         cl_int error;
314                         error = clGetPlatformIDs(0, 0, &numberOfPlatforms);
315                         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
316                         if (G.f & G_DEBUG) printf("%d number of platforms\n", numberOfPlatforms);
317                         cl_platform_id *platforms = (cl_platform_id *)MEM_mallocN(sizeof(cl_platform_id) * numberOfPlatforms, __func__);
318                         error = clGetPlatformIDs(numberOfPlatforms, platforms, 0);
319                         unsigned int indexPlatform;
320                         for (indexPlatform = 0; indexPlatform < numberOfPlatforms; indexPlatform++) {
321                                 cl_platform_id platform = platforms[indexPlatform];
322                                 cl_uint numberOfDevices = 0;
323                                 clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, 0, &numberOfDevices);
324                                 if (numberOfDevices <= 0)
325                                         continue;
326
327                                 cl_device_id *cldevices = (cl_device_id *)MEM_mallocN(sizeof(cl_device_id) * numberOfDevices, __func__);
328                                 clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numberOfDevices, cldevices, 0);
329
330                                 g_context = clCreateContext(NULL, numberOfDevices, cldevices, clContextError, NULL, &error);
331                                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
332                                 const char *cl_str[2] = {datatoc_COM_OpenCLKernels_cl, NULL};
333                                 g_program = clCreateProgramWithSource(g_context, 1, cl_str, 0, &error);
334                                 error = clBuildProgram(g_program, numberOfDevices, cldevices, 0, 0, 0);
335                                 if (error != CL_SUCCESS) { 
336                                         cl_int error2;
337                                         size_t ret_val_size = 0;
338                                         printf("CLERROR[%d]: %s\n", error, clewErrorString(error));     
339                                         error2 = clGetProgramBuildInfo(g_program, cldevices[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
340                                         if (error2 != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
341                                         char *build_log = (char *)MEM_mallocN(sizeof(char) * ret_val_size + 1, __func__);
342                                         error2 = clGetProgramBuildInfo(g_program, cldevices[0], CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
343                                         if (error2 != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
344                                         build_log[ret_val_size] = '\0';
345                                         printf("%s", build_log);
346                                         MEM_freeN(build_log);
347                                 }
348                                 else {
349                                         unsigned int indexDevices;
350                                         for (indexDevices = 0; indexDevices < numberOfDevices; indexDevices++) {
351                                                 cl_device_id device = cldevices[indexDevices];
352                                                 cl_int vendorID = 0;
353                                                 cl_int error2 = clGetDeviceInfo(device, CL_DEVICE_VENDOR_ID, sizeof(cl_int), &vendorID, NULL);
354                                                 if (error2 != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error2, clewErrorString(error2)); }
355                                                 OpenCLDevice *clDevice = new OpenCLDevice(g_context, device, g_program, vendorID);
356                                                 clDevice->initialize();
357                                                 g_gpudevices.push_back(clDevice);
358                                         }
359                                 }
360                                 MEM_freeN(cldevices);
361                         }
362                         MEM_freeN(platforms);
363                 }
364
365                 g_openclInitialized = true;
366         }
367 #endif
368 #endif
369 }
370
371 void WorkScheduler::deinitialize()
372 {
373 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
374         /* deinitialize CPU threads */
375         if (g_cpuInitialized) {
376                 Device *device;
377                 while (g_cpudevices.size() > 0) {
378                         device = g_cpudevices.back();
379                         g_cpudevices.pop_back();
380                         device->deinitialize();
381                         delete device;
382                 }
383
384                 g_cpuInitialized = false;
385         }
386
387 #ifdef COM_OPENCL_ENABLED
388         /* deinitialize OpenCL GPU's */
389         if (g_openclInitialized) {
390                 Device *device;
391                 while (g_gpudevices.size() > 0) {
392                         device = g_gpudevices.back();
393                         g_gpudevices.pop_back();
394                         device->deinitialize();
395                         delete device;
396                 }
397                 if (g_program) {
398                         clReleaseProgram(g_program);
399                         g_program = NULL;
400                 }
401                 if (g_context) {
402                         clReleaseContext(g_context);
403                         g_context = NULL;
404                 }
405
406                 g_openclInitialized = false;
407         }
408 #endif
409 #endif
410
411         /* deinitialize highlighting */
412         if (g_highlightInitialized) {
413                 g_highlightInitialized = false;
414                 if (g_highlightedNodes) {
415                         MEM_freeN(g_highlightedNodes);
416                         g_highlightedNodes = NULL;
417                 }
418
419                 if (g_highlightedNodesRead) {
420                         MEM_freeN(g_highlightedNodesRead);
421                         g_highlightedNodesRead = NULL;
422                 }
423         }
424 }
425