Cycles: threading optimizations
[blender.git] / intern / cycles / render / image.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 "device.h"
20 #include "image.h"
21 #include "scene.h"
22
23 #include "util_foreach.h"
24 #include "util_image.h"
25 #include "util_path.h"
26 #include "util_progress.h"
27
28 #ifdef WITH_OSL
29 #include <OSL/oslexec.h>
30 #endif
31
32 CCL_NAMESPACE_BEGIN
33
34 ImageManager::ImageManager()
35 {
36         need_update = true;
37         osl_texture_system = NULL;
38 }
39
40 ImageManager::~ImageManager()
41 {
42         for(size_t slot = 0; slot < images.size(); slot++)
43                 assert(!images[slot]);
44         for(size_t slot = 0; slot < float_images.size(); slot++)
45                 assert(!float_images[slot]);
46 }
47
48 void ImageManager::set_osl_texture_system(void *texture_system)
49 {
50         osl_texture_system = texture_system;
51 }
52
53 static bool is_float_image(const string& filename)
54 {
55         ImageInput *in = ImageInput::create(filename);
56         bool is_float = false;
57
58         if(in) {
59                 ImageSpec spec;
60
61                 if(in->open(filename, spec)) {
62                         /* check the main format, and channel formats;
63                            if any are non-integer, we'll need a float texture slot */
64                         if(spec.format == TypeDesc::HALF ||
65                            spec.format == TypeDesc::FLOAT ||
66                            spec.format == TypeDesc::DOUBLE) {
67                                 is_float = true;
68                         }
69
70                         for(size_t channel = 0; channel < spec.channelformats.size(); channel++) {
71                                 if(spec.channelformats[channel] == TypeDesc::HALF ||
72                                    spec.channelformats[channel] == TypeDesc::FLOAT ||
73                                    spec.channelformats[channel] == TypeDesc::DOUBLE) {
74                                         is_float = true;
75                                 }
76                         }
77
78                         in->close();
79                 }
80
81                 delete in;
82         }
83
84         return is_float;
85 }
86
87 int ImageManager::add_image(const string& filename, bool& is_float)
88 {
89         Image *img;
90         size_t slot;
91
92         /* load image info and find out if we need a float texture */
93         is_float = is_float_image(filename);
94
95         if(is_float) {
96                 /* find existing image */
97                 for(slot = 0; slot < float_images.size(); slot++) {
98                         if(float_images[slot] && float_images[slot]->filename == filename) {
99                                 float_images[slot]->users++;
100                                 return slot+TEX_IMAGE_FLOAT_START;
101                         }
102                 }
103
104                 /* find free slot */
105                 for(slot = 0; slot < float_images.size(); slot++) {
106                         if(!float_images[slot])
107                                 break;
108                 }
109
110                 if(slot == float_images.size()) {
111                         /* max images limit reached */
112                         if(float_images.size() == TEX_NUM_FLOAT_IMAGES)
113                                 return -1;
114
115                         float_images.resize(float_images.size() + 1);
116                 }
117
118                 /* add new image */
119                 img = new Image();
120                 img->filename = filename;
121                 img->need_load = true;
122                 img->users = 1;
123
124                 float_images[slot] = img;
125                 /* report slot out of total set of textures */
126                 slot += TEX_IMAGE_FLOAT_START;
127         }
128         else {
129                 for(slot = 0; slot < images.size(); slot++) {
130                         if(images[slot] && images[slot]->filename == filename) {
131                                 images[slot]->users++;
132                                 return slot;
133                         }
134                 }
135
136                 /* find free slot */
137                 for(slot = 0; slot < images.size(); slot++) {
138                         if(!images[slot])
139                                 break;
140                 }
141
142                 if(slot == images.size()) {
143                         /* max images limit reached */
144                         if(images.size() == TEX_NUM_IMAGES)
145                                 return -1;
146
147                         images.resize(images.size() + 1);
148                 }
149
150                 /* add new image */
151                 img = new Image();
152                 img->filename = filename;
153                 img->need_load = true;
154                 img->users = 1;
155
156                 images[slot] = img;
157         }
158         need_update = true;
159
160         return slot;
161 }
162
163 void ImageManager::remove_image(const string& filename)
164 {
165         size_t slot;
166
167         for(slot = 0; slot < images.size(); slot++) {
168                 if(images[slot] && images[slot]->filename == filename) {
169                         /* decrement user count */
170                         images[slot]->users--;
171                         assert(images[slot]->users >= 0);
172
173                         /* don't remove immediately, rather do it all together later on. one of
174                            the reasons for this is that on shader changes we add and remove nodes
175                            that use them, but we do not want to reload the image all the time. */
176                         if(images[slot]->users == 0)
177                                 need_update = true;
178
179                         break;
180                 }
181         }
182
183         if(slot == images.size()) {
184                 /* see if it's in a float texture slot */
185                 for(slot = 0; slot < float_images.size(); slot++) {
186                         if(float_images[slot] && float_images[slot]->filename == filename) {
187                                 /* decrement user count */
188                                 float_images[slot]->users--;
189                                 assert(float_images[slot]->users >= 0);
190
191                                 /* don't remove immediately, rather do it all together later on. one of
192                                    the reasons for this is that on shader changes we add and remove nodes
193                                    that use them, but we do not want to reload the image all the time. */
194                                 if(float_images[slot]->users == 0)
195                                         need_update = true;
196
197                                 break;
198                         }
199                 }
200         }
201 }
202
203 bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
204 {
205         if(img->filename == "")
206                 return false;
207
208         /* load image from file through OIIO */
209         ImageInput *in = ImageInput::create(img->filename);
210
211         if(!in)
212                 return false;
213
214         ImageSpec spec;
215
216         if(!in->open(img->filename, spec)) {
217                 delete in;
218                 return false;
219         }
220
221         /* we only handle certain number of components */
222         int width = spec.width;
223         int height = spec.height;
224         int components = spec.nchannels;
225
226         if(!(components == 1 || components == 3 || components == 4)) {
227                 in->close();
228                 delete in;
229                 return false;
230         }
231
232         /* read RGBA pixels */
233         uchar *pixels = (uchar*)tex_img.resize(width, height);
234         int scanlinesize = width*components*sizeof(uchar);
235
236         in->read_image(TypeDesc::UINT8,
237                 (uchar*)pixels + (height-1)*scanlinesize,
238                 AutoStride,
239                 -scanlinesize,
240                 AutoStride);
241
242         in->close();
243         delete in;
244
245         if(components == 3) {
246                 for(int i = width*height-1; i >= 0; i--) {
247                         pixels[i*4+3] = 255;
248                         pixels[i*4+2] = pixels[i*3+2];
249                         pixels[i*4+1] = pixels[i*3+1];
250                         pixels[i*4+0] = pixels[i*3+0];
251                 }
252         }
253         else if(components == 1) {
254                 for(int i = width*height-1; i >= 0; i--) {
255                         pixels[i*4+3] = 255;
256                         pixels[i*4+2] = pixels[i];
257                         pixels[i*4+1] = pixels[i];
258                         pixels[i*4+0] = pixels[i];
259                 }
260         }
261
262         return true;
263 }
264
265 bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_img)
266 {
267         if(img->filename == "")
268                 return false;
269
270         /* load image from file through OIIO */
271         ImageInput *in = ImageInput::create(img->filename);
272
273         if(!in)
274                 return false;
275
276         ImageSpec spec;
277
278         if(!in->open(img->filename, spec)) {
279                 delete in;
280                 return false;
281         }
282
283         /* we only handle certain number of components */
284         int width = spec.width;
285         int height = spec.height;
286         int components = spec.nchannels;
287
288         if(!(components == 1 || components == 3 || components == 4)) {
289                 in->close();
290                 delete in;
291                 return false;
292         }
293
294         /* read RGBA pixels */
295         float *pixels = (float*)tex_img.resize(width, height);
296         int scanlinesize = width*components*sizeof(float);
297
298         in->read_image(TypeDesc::FLOAT,
299                 (uchar*)pixels + (height-1)*scanlinesize,
300                 AutoStride,
301                 -scanlinesize,
302                 AutoStride);
303
304         in->close();
305         delete in;
306
307         if(components == 3) {
308                 for(int i = width*height-1; i >= 0; i--) {
309                         pixels[i*4+3] = 1.0f;
310                         pixels[i*4+2] = pixels[i*3+2];
311                         pixels[i*4+1] = pixels[i*3+1];
312                         pixels[i*4+0] = pixels[i*3+0];
313                 }
314         }
315         else if(components == 1) {
316                 for(int i = width*height-1; i >= 0; i--) {
317                         pixels[i*4+3] = 1.0f;
318                         pixels[i*4+2] = pixels[i];
319                         pixels[i*4+1] = pixels[i];
320                         pixels[i*4+0] = pixels[i];
321                 }
322         }
323
324         return true;
325 }
326
327 void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int slot, Progress *progress)
328 {
329         if(progress->get_cancel())
330                 return;
331         if(osl_texture_system)
332                 return;
333
334         Image *img;
335         bool is_float;
336
337         if(slot < TEX_IMAGE_FLOAT_START) {
338                 img = images[slot];
339                 is_float = false;
340         }
341         else {
342                 img = float_images[slot - TEX_IMAGE_FLOAT_START];
343                 is_float = true;
344         }
345
346         if(is_float) {
347                 string filename = path_filename(float_images[slot]->filename);
348                 progress->set_status("Updating Images", "Loading " + filename);
349
350                 device_vector<float4>& tex_img = dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START];
351
352                 if(tex_img.device_pointer)
353                         device->tex_free(tex_img);
354
355                 if(!file_load_float_image(img, tex_img)) {
356                         /* on failure to load, we set a 1x1 pixels black image */
357                         float *pixels = (float*)tex_img.resize(1, 1);
358
359                         pixels[0] = 0.0f;
360                         pixels[1] = 0.0f;
361                         pixels[2] = 0.0f;
362                         pixels[3] = 0.0f;
363                 }
364
365                 string name;
366
367                 if(slot >= 10) name = string_printf("__tex_image_float_0%d", slot);
368                 else name = string_printf("__tex_image_float_00%d", slot);
369
370                 device->tex_alloc(name.c_str(), tex_img, true, true);
371         }
372         else {
373                 string filename = path_filename(images[slot]->filename);
374                 progress->set_status("Updating Images", "Loading " + filename);
375
376                 device_vector<uchar4>& tex_img = dscene->tex_image[slot];
377
378                 if(tex_img.device_pointer)
379                         device->tex_free(tex_img);
380
381                 if(!file_load_image(img, tex_img)) {
382                         /* on failure to load, we set a 1x1 pixels black image */
383                         uchar *pixels = (uchar*)tex_img.resize(1, 1);
384
385                         pixels[0] = 0;
386                         pixels[1] = 0;
387                         pixels[2] = 0;
388                         pixels[3] = 0;
389                 }
390
391                 string name;
392
393                 if(slot >= 10) name = string_printf("__tex_image_0%d", slot);
394                 else name = string_printf("__tex_image_00%d", slot);
395
396                 device->tex_alloc(name.c_str(), tex_img, true, true);
397         }
398
399         img->need_load = false;
400 }
401
402 void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int slot)
403 {
404         Image *img;
405         bool is_float;
406
407         if(slot < TEX_IMAGE_FLOAT_START) {
408                 img = images[slot];
409                 is_float = false;
410         }
411         else {
412                 img = float_images[slot - TEX_IMAGE_FLOAT_START];
413                 is_float = true;
414         }
415
416         if(img) {
417                 if(osl_texture_system) {
418 #ifdef WITH_OSL
419                         ustring filename(images[slot]->filename);
420                         ((OSL::TextureSystem*)osl_texture_system)->invalidate(filename);
421 #endif
422                 }
423                 else if(is_float) {
424                         device->tex_free(dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START]);
425                         dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START].clear();
426
427                         delete float_images[slot - TEX_IMAGE_FLOAT_START];
428                         float_images[slot - TEX_IMAGE_FLOAT_START] = NULL;
429                 }
430                 else {
431                         device->tex_free(dscene->tex_image[slot]);
432                         dscene->tex_image[slot].clear();
433
434                         delete images[slot];
435                         images[slot] = NULL;
436                 }
437         }
438 }
439
440 void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& progress)
441 {
442         if(!need_update)
443                 return;
444         
445         TaskPool pool;
446
447         for(size_t slot = 0; slot < images.size(); slot++) {
448                 if(!images[slot])
449                         continue;
450
451                 if(images[slot]->users == 0) {
452                         device_free_image(device, dscene, slot);
453                 }
454                 else if(images[slot]->need_load) {
455                         if(!osl_texture_system) 
456                                 pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress));
457                 }
458         }
459
460         for(size_t slot = 0; slot < float_images.size(); slot++) {
461                 if(!float_images[slot])
462                         continue;
463
464                 if(float_images[slot]->users == 0) {
465                         device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
466                 }
467                 else if(float_images[slot]->need_load) {
468                         if(!osl_texture_system) 
469                                 pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + TEX_IMAGE_FLOAT_START, &progress));
470                 }
471         }
472
473         pool.wait_work();
474
475         need_update = false;
476 }
477
478 void ImageManager::device_free(Device *device, DeviceScene *dscene)
479 {
480         for(size_t slot = 0; slot < images.size(); slot++)
481                 device_free_image(device, dscene, slot);
482         for(size_t slot = 0; slot < float_images.size(); slot++)
483                 device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
484
485         images.clear();
486         float_images.clear();
487 }
488
489 CCL_NAMESPACE_END
490