Moved highlight code to the workscheduler.
[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_WorkScheduler.h"
29 #include "COM_CPUDevice.h"
30 #include "COM_OpenCLDevice.h"
31 #include "COM_OpenCLKernels.cl.h"
32 #include "OCL_opencl.h"
33 #include "COM_WriteBufferOperation.h"
34
35 #include "PIL_time.h"
36 #include "BLI_threads.h"
37
38 #if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD
39 #warning COM_CURRENT_THREADING_MODEL COM_TM_NOTHREAD is activated. Use only for debugging.
40 #elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
41 #else
42 #error COM_CURRENT_THREADING_MODEL No threading model selected
43 #endif
44
45
46 /// @brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
47 static vector<CPUDevice *> g_cpudevices;
48
49 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
50 /// @brief list of all thread for every CPUDevice in cpudevices a thread exists
51 static ListBase g_cputhreads;
52 /// @brief all scheduled work for the cpu
53 static ThreadQueue *g_cpuqueue;
54 static ThreadQueue *g_gpuqueue;
55 #ifdef COM_OPENCL_ENABLED
56 static cl_context g_context;
57 static cl_program g_program;
58 /// @brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is created
59 static vector<OpenCLDevice *> g_gpudevices;
60 /// @brief list of all thread for every GPUDevice in cpudevices a thread exists
61 static ListBase g_gputhreads;
62 /// @brief all scheduled work for the gpu
63 #ifdef COM_OPENCL_ENABLED
64 static bool g_openclActive = false;
65 #endif
66 #endif
67 #endif
68
69 #define HIGHLIGHT(wp) \
70 { \
71         ExecutionGroup* group = wp->getExecutionGroup(); \
72         if (group->isComplex()) { \
73                 NodeOperation* operation = group->getOutputNodeOperation(); \
74                 if (operation->isWriteBufferOperation()) {\
75                         WriteBufferOperation *writeOperation = (WriteBufferOperation*)operation;\
76                         NodeOperation *complexOperation = writeOperation->getInput(); \
77                         bNode *node = complexOperation->getbNode(); \
78                         if (node) { \
79                                 if (node->original) { \
80                                         node->original->highlight = 1;\
81                                 } else {\
82                                         node->highlight = 1; \
83                                 }\
84                         } \
85                 } \
86         } \
87 }
88
89 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
90 void *WorkScheduler::thread_execute_cpu(void *data)
91 {
92         Device *device = (Device *)data;
93         WorkPackage *work;
94         
95         while ((work = (WorkPackage *)BLI_thread_queue_pop(g_cpuqueue))) {
96                 HIGHLIGHT(work);
97                 device->execute(work);
98                 delete work;
99         }
100         
101         return NULL;
102 }
103
104 void *WorkScheduler::thread_execute_gpu(void *data)
105 {
106         Device *device = (Device *)data;
107         WorkPackage *work;
108         
109         while ((work = (WorkPackage *)BLI_thread_queue_pop(g_gpuqueue))) {
110                 HIGHLIGHT(work);
111                 device->execute(work);
112                 delete work;
113         }
114         
115         return NULL;
116 }
117 #endif
118
119
120
121 void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber)
122 {
123         WorkPackage *package = new WorkPackage(group, chunkNumber);
124 #if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD
125         CPUDevice device;
126         device.execute(package);
127         delete package;
128 #elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
129 #ifdef COM_OPENCL_ENABLED
130         if (group->isOpenCL() && g_openclActive) {
131                 BLI_thread_queue_push(g_gpuqueue, package);
132         }
133         else {
134                 BLI_thread_queue_push(g_cpuqueue, package);
135         }
136 #else
137         BLI_thread_queue_push(cpuqueue, package);
138 #endif
139 #endif
140 }
141
142 void WorkScheduler::start(CompositorContext &context)
143 {
144 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
145         unsigned int index;
146         g_cpuqueue = BLI_thread_queue_init();
147         BLI_init_threads(&g_cputhreads, thread_execute_cpu, g_cpudevices.size());
148         for (index = 0; index < g_cpudevices.size(); index++) {
149                 Device *device = g_cpudevices[index];
150                 BLI_insert_thread(&g_cputhreads, device);
151         }
152 #ifdef COM_OPENCL_ENABLED
153         if (context.getHasActiveOpenCLDevices()) {
154                 g_gpuqueue = BLI_thread_queue_init();
155                 BLI_init_threads(&g_gputhreads, thread_execute_gpu, g_gpudevices.size());
156                 for (index = 0; index < g_gpudevices.size(); index++) {
157                         Device *device = g_gpudevices[index];
158                         BLI_insert_thread(&g_gputhreads, device);
159                 }
160                 g_openclActive = true;
161         }
162         else {
163                 g_openclActive = false;
164         }
165 #endif
166 #endif
167 }
168 void WorkScheduler::finish()
169 {
170 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
171 #ifdef COM_OPENCL_ENABLED
172         if (g_openclActive) {
173                 BLI_thread_queue_wait_finish(g_gpuqueue);
174                 BLI_thread_queue_wait_finish(g_cpuqueue);
175         }
176         else {
177                 BLI_thread_queue_wait_finish(g_cpuqueue);
178         }
179 #else
180         BLI_thread_queue_wait_finish(cpuqueue);
181 #endif
182 #endif
183 }
184 void WorkScheduler::stop()
185 {
186 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
187         BLI_thread_queue_nowait(g_cpuqueue);
188         BLI_end_threads(&g_cputhreads);
189         BLI_thread_queue_free(g_cpuqueue);
190         g_cpuqueue = NULL;
191 #ifdef COM_OPENCL_ENABLED
192         if (g_openclActive) {
193                 BLI_thread_queue_nowait(g_gpuqueue);
194                 BLI_end_threads(&g_gputhreads);
195                 BLI_thread_queue_free(g_gpuqueue);
196                 g_gpuqueue = NULL;
197         }
198 #endif
199 #endif
200 }
201
202 bool WorkScheduler::hasGPUDevices()
203 {
204 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
205 #ifdef COM_OPENCL_ENABLED
206         return g_gpudevices.size() > 0;
207 #else
208         return 0;
209 #endif
210 #else
211         return 0;
212 #endif
213 }
214
215 extern void clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data)
216 {
217         printf("OPENCL error: %s\n", errinfo);
218 }
219
220 void WorkScheduler::initialize()
221 {
222 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
223         int numberOfCPUThreads = BLI_system_thread_count();
224
225         for (int index = 0; index < numberOfCPUThreads; index++) {
226                 CPUDevice *device = new CPUDevice();
227                 device->initialize();
228                 g_cpudevices.push_back(device);
229         }
230 #ifdef COM_OPENCL_ENABLED
231         g_context = NULL;
232         g_program = NULL;
233         if (clCreateContextFromType) {
234                 cl_uint numberOfPlatforms = 0;
235                 cl_int error;
236                 error = clGetPlatformIDs(0, 0, &numberOfPlatforms);
237                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
238                 if (G.f & G_DEBUG) printf("%d number of platforms\n", numberOfPlatforms);
239                 cl_platform_id *platforms = new cl_platform_id[numberOfPlatforms];
240                 error = clGetPlatformIDs(numberOfPlatforms, platforms, 0);
241                 unsigned int indexPlatform;
242                 for (indexPlatform = 0; indexPlatform < numberOfPlatforms; indexPlatform++) {
243                         cl_platform_id platform = platforms[indexPlatform];
244                         cl_uint numberOfDevices = 0;
245                         clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, 0, &numberOfDevices);
246                         if (numberOfDevices>0) {
247                                 cl_device_id *cldevices = new cl_device_id[numberOfDevices];
248                                 clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numberOfDevices, cldevices, 0);
249
250                                 g_context = clCreateContext(NULL, numberOfDevices, cldevices, clContextError, NULL, &error);
251                                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
252                                 g_program = clCreateProgramWithSource(g_context, 1, &clkernelstoh_COM_OpenCLKernels_cl, 0, &error);
253                                 error = clBuildProgram(g_program, numberOfDevices, cldevices, 0, 0, 0);
254                                 if (error != CL_SUCCESS) { 
255                                         cl_int error2;
256                                         size_t ret_val_size = 0;
257                                         printf("CLERROR[%d]: %s\n", error, clewErrorString(error));     
258                                         error2 = clGetProgramBuildInfo(g_program, cldevices[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
259                                         if (error2 != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
260                                         char *build_log =  new char[ret_val_size + 1];
261                                         error2 = clGetProgramBuildInfo(g_program, cldevices[0], CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
262                                         if (error2 != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
263                                         build_log[ret_val_size] = '\0';
264                                         printf("%s", build_log);
265                                         delete build_log;
266                                 }
267                                 else {
268                                         unsigned int indexDevices;
269                                         for (indexDevices = 0; indexDevices < numberOfDevices; indexDevices++) {
270                                                 cl_device_id device = cldevices[indexDevices];
271                                                 cl_int vendorID = 0;
272                                                 cl_int error2 = clGetDeviceInfo(device, CL_DEVICE_VENDOR_ID, sizeof(cl_int), &vendorID, NULL);
273                                                 if (error2 != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error2, clewErrorString(error2)); }
274                                                 OpenCLDevice *clDevice = new OpenCLDevice(g_context, device, g_program, vendorID);
275                                                 clDevice->initialize();
276                                                 g_gpudevices.push_back(clDevice);
277                                         }
278                                 }
279                                 delete[] cldevices;
280                         }
281                 }
282                 delete[] platforms;
283         }
284 #endif
285 #endif
286 }
287
288 void WorkScheduler::deinitialize()
289 {
290 #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
291         Device *device;
292         while (g_cpudevices.size() > 0) {
293                 device = g_cpudevices.back();
294                 g_cpudevices.pop_back();
295                 device->deinitialize();
296                 delete device;
297         }
298 #ifdef COM_OPENCL_ENABLED
299         while (g_gpudevices.size() > 0) {
300                 device = g_gpudevices.back();
301                 g_gpudevices.pop_back();
302                 device->deinitialize();
303                 delete device;
304         }
305         if (g_program) {
306                 clReleaseProgram(g_program);
307                 g_program = NULL;
308         }
309         if (g_context) {
310                 clReleaseContext(g_context);
311                 g_context = NULL;
312         }
313 #endif
314 #endif
315 }