ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / render / merge.cpp
1 /*
2  * Copyright 2011-2019 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 "render/merge.h"
18
19 #include "util/util_array.h"
20 #include "util/util_map.h"
21 #include "util/util_system.h"
22 #include "util/util_time.h"
23 #include "util/util_unique_ptr.h"
24
25 #include <OpenImageIO/imageio.h>
26 #include <OpenImageIO/filesystem.h>
27
28 OIIO_NAMESPACE_USING
29
30 CCL_NAMESPACE_BEGIN
31
32 /* Merge Image Layer */
33
34 enum MergeChannelOp {
35   MERGE_CHANNEL_NOP,
36   MERGE_CHANNEL_COPY,
37   MERGE_CHANNEL_SUM,
38   MERGE_CHANNEL_AVERAGE
39 };
40
41 struct MergeImagePass {
42   /* Full channel name. */
43   string channel_name;
44   /* Channel format in the file. */
45   TypeDesc format;
46   /* Type of operation to perform when merging. */
47   MergeChannelOp op;
48   /* Offset of layer channels in input image. */
49   int offset;
50   /* Offset of layer channels in merged image. */
51   int merge_offset;
52 };
53
54 struct MergeImageLayer {
55   /* Layer name. */
56   string name;
57   /* Passes. */
58   vector<MergeImagePass> passes;
59   /* Sample amount that was used for rendering this layer. */
60   int samples;
61 };
62
63 /* Merge Image */
64
65 struct MergeImage {
66   /* OIIO file handle. */
67   unique_ptr<ImageInput> in;
68   /* Image file path. */
69   string filepath;
70   /* Render layers. */
71   vector<MergeImageLayer> layers;
72 };
73
74 /* Channel Parsing */
75
76 static MergeChannelOp parse_channel_operation(const string &pass_name)
77 {
78   if (pass_name == "Depth" || pass_name == "IndexMA" || pass_name == "IndexOB" ||
79       string_startswith(pass_name, "Crypto")) {
80     return MERGE_CHANNEL_COPY;
81   }
82   else if (string_startswith(pass_name, "Debug BVH") ||
83            string_startswith(pass_name, "Debug Ray") ||
84            string_startswith(pass_name, "Debug Render Time")) {
85     return MERGE_CHANNEL_SUM;
86   }
87   else {
88     return MERGE_CHANNEL_AVERAGE;
89   }
90 }
91
92 /* Splits in at its last dot, setting suffix to the part after the dot and
93  * into the part before it. Returns whether a dot was found. */
94 static bool split_last_dot(string &in, string &suffix)
95 {
96   size_t pos = in.rfind(".");
97   if (pos == string::npos) {
98     return false;
99   }
100   suffix = in.substr(pos + 1);
101   in = in.substr(0, pos);
102   return true;
103 }
104
105 /* Separate channel names as generated by Blender.
106  * Multiview format: RenderLayer.Pass.View.Channel
107  * Otherwise: RenderLayer.Pass.Channel */
108 static bool parse_channel_name(
109     string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
110 {
111   if (!split_last_dot(name, channel)) {
112     return false;
113   }
114   string view;
115   if (multiview_channels && !split_last_dot(name, view)) {
116     return false;
117   }
118   if (!split_last_dot(name, pass)) {
119     return false;
120   }
121   renderlayer = name;
122
123   if (multiview_channels) {
124     renderlayer += "." + view;
125   }
126
127   return true;
128 }
129
130 static bool parse_channels(const ImageSpec &in_spec,
131                            vector<MergeImageLayer> &layers,
132                            string &error)
133 {
134   const ParamValue *multiview = in_spec.find_attribute("multiView");
135   const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
136                                    multiview->type().arraylen >= 2);
137
138   layers.clear();
139
140   /* Loop over all the channels in the file, parse their name and sort them
141    * by RenderLayer.
142    * Channels that can't be parsed are directly passed through to the output. */
143   map<string, MergeImageLayer> file_layers;
144   for (int i = 0; i < in_spec.nchannels; i++) {
145     MergeImagePass pass;
146     pass.channel_name = in_spec.channelnames[i];
147     pass.format = (in_spec.channelformats.size() > 0) ? in_spec.channelformats[i] : in_spec.format;
148     pass.offset = i;
149     pass.merge_offset = i;
150
151     string layername, passname, channelname;
152     if (parse_channel_name(
153             pass.channel_name, layername, passname, channelname, multiview_channels)) {
154       /* Channer part of a render layer. */
155       pass.op = parse_channel_operation(passname);
156     }
157     else {
158       /* Other channels are added in unnamed layer. */
159       layername = "";
160       pass.op = parse_channel_operation(pass.channel_name);
161     }
162
163     file_layers[layername].passes.push_back(pass);
164   }
165
166   /* Loop over all detected RenderLayers, check whether they contain a full set of input channels.
167    * Any channels that won't be processed internally are also passed through. */
168   for (auto &i : file_layers) {
169     const string &name = i.first;
170     MergeImageLayer &layer = i.second;
171
172     layer.name = name;
173     layer.samples = 0;
174
175     /* Determine number of samples from metadata. */
176     if (layer.name == "") {
177       layer.samples = 1;
178     }
179     else if (layer.samples < 1) {
180       string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", "");
181       if (sample_string != "") {
182         if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) {
183           error = "Failed to parse samples metadata: " + sample_string;
184           return false;
185         }
186       }
187     }
188
189     if (layer.samples < 1) {
190       error = string_printf(
191           "No sample number specified in the file for layer %s or on the command line",
192           name.c_str());
193       return false;
194     }
195
196     layers.push_back(layer);
197   }
198
199   return true;
200 }
201
202 static bool open_images(const vector<string> &filepaths, vector<MergeImage> &images, string &error)
203 {
204   for (const string &filepath : filepaths) {
205     unique_ptr<ImageInput> in(ImageInput::open(filepath));
206     if (!in) {
207       error = "Couldn't open file: " + filepath;
208       return false;
209     }
210
211     MergeImage image;
212     image.in = std::move(in);
213     image.filepath = filepath;
214     if (!parse_channels(image.in->spec(), image.layers, error)) {
215       return false;
216     }
217
218     if (image.layers.size() == 0) {
219       error = "Could not find a render layer for merging";
220       return false;
221     }
222
223     if (image.in->spec().deep) {
224       error = "Merging deep images not supported.";
225       return false;
226     }
227
228     if (images.size() > 0) {
229       const ImageSpec &base_spec = images[0].in->spec();
230       const ImageSpec &spec = image.in->spec();
231
232       if (base_spec.width != spec.width || base_spec.height != spec.height ||
233           base_spec.depth != spec.depth || base_spec.format != spec.format ||
234           base_spec.deep != spec.deep) {
235         error = "Images do not have matching size and data layout.";
236         return false;
237       }
238     }
239
240     images.push_back(std::move(image));
241   }
242
243   return true;
244 }
245
246 static void merge_render_time(ImageSpec &spec,
247                               const vector<MergeImage> &images,
248                               const string &name,
249                               const bool average)
250 {
251   double time = 0.0;
252
253   for (const MergeImage &image : images) {
254     string time_str = image.in->spec().get_string_attribute(name, "");
255     time += time_human_readable_to_seconds(time_str);
256   }
257
258   if (average) {
259     time /= images.size();
260   }
261
262   spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
263 }
264
265 static void merge_layer_render_time(ImageSpec &spec,
266                                     const vector<MergeImage> &images,
267                                     const string &layer_name,
268                                     const string &time_name,
269                                     const bool average)
270 {
271   string name = "cycles." + layer_name + "." + time_name;
272   double time = 0.0;
273
274   for (const MergeImage &image : images) {
275     string time_str = image.in->spec().get_string_attribute(name, "");
276     time += time_human_readable_to_seconds(time_str);
277   }
278
279   if (average) {
280     time /= images.size();
281   }
282
283   spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
284 }
285
286 static void merge_channels_metadata(vector<MergeImage> &images,
287                                     ImageSpec &out_spec,
288                                     vector<int> &channel_total_samples)
289 {
290   /* Based on first image. */
291   out_spec = images[0].in->spec();
292
293   /* Merge channels and compute offsets. */
294   out_spec.nchannels = 0;
295   out_spec.channelformats.clear();
296   out_spec.channelnames.clear();
297
298   for (MergeImage &image : images) {
299     for (MergeImageLayer &layer : image.layers) {
300       for (MergeImagePass &pass : layer.passes) {
301         /* Test if matching channel already exists in merged image. */
302         bool found = false;
303
304         for (size_t i = 0; i < out_spec.nchannels; i++) {
305           if (pass.channel_name == out_spec.channelnames[i]) {
306             pass.merge_offset = i;
307             channel_total_samples[i] += layer.samples;
308             /* First image wins for channels that can't be averaged or summed. */
309             if (pass.op == MERGE_CHANNEL_COPY) {
310               pass.op = MERGE_CHANNEL_NOP;
311             }
312             found = true;
313             break;
314           }
315         }
316
317         if (!found) {
318           /* Add new channel. */
319           pass.merge_offset = out_spec.nchannels;
320           channel_total_samples.push_back(layer.samples);
321
322           out_spec.channelnames.push_back(pass.channel_name);
323           out_spec.channelformats.push_back(pass.format);
324           out_spec.nchannels++;
325         }
326       }
327     }
328   }
329
330   /* Merge metadata. */
331   merge_render_time(out_spec, images, "RenderTime", false);
332
333   map<string, int> layer_num_samples;
334   for (MergeImage &image : images) {
335     for (MergeImageLayer &layer : image.layers) {
336       if (layer.name != "") {
337         layer_num_samples[layer.name] += layer.samples;
338       }
339     }
340   }
341
342   for (const auto &i : layer_num_samples) {
343     string name = "cycles." + i.first + ".samples";
344     out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", i.second));
345
346     merge_layer_render_time(out_spec, images, i.first, "total_time", false);
347     merge_layer_render_time(out_spec, images, i.first, "render_time", false);
348     merge_layer_render_time(out_spec, images, i.first, "synchronization_time", true);
349   }
350 }
351
352 static void alloc_pixels(const ImageSpec &spec, array<float> &pixels)
353 {
354   const size_t width = spec.width;
355   const size_t height = spec.height;
356   const size_t num_channels = spec.nchannels;
357
358   const size_t num_pixels = (size_t)width * (size_t)height;
359   pixels.resize(num_pixels * num_channels);
360 }
361
362 static bool merge_pixels(const vector<MergeImage> &images,
363                          const ImageSpec &out_spec,
364                          const vector<int> &channel_total_samples,
365                          array<float> &out_pixels,
366                          string &error)
367 {
368   alloc_pixels(out_spec, out_pixels);
369   memset(out_pixels.data(), 0, out_pixels.size() * sizeof(float));
370
371   for (const MergeImage &image : images) {
372     /* Read all channels into buffer. Reading all channels at once is
373      * faster than individually due to interleaved EXR channel storage. */
374     array<float> pixels;
375     alloc_pixels(image.in->spec(), pixels);
376
377     if (!image.in->read_image(TypeDesc::FLOAT, pixels.data())) {
378       error = "Failed to read image: " + image.filepath;
379       return false;
380     }
381
382     for (size_t li = 0; li < image.layers.size(); li++) {
383       const MergeImageLayer &layer = image.layers[li];
384
385       const size_t stride = image.in->spec().nchannels;
386       const size_t out_stride = out_spec.nchannels;
387       const size_t num_pixels = pixels.size();
388
389       for (const MergeImagePass &pass : layer.passes) {
390         size_t offset = pass.offset;
391         size_t out_offset = pass.merge_offset;
392
393         switch (pass.op) {
394           case MERGE_CHANNEL_NOP:
395             break;
396           case MERGE_CHANNEL_COPY:
397             for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
398               out_pixels[out_offset] = pixels[offset];
399             }
400             break;
401           case MERGE_CHANNEL_SUM:
402             for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
403               out_pixels[out_offset] += pixels[offset];
404             }
405             break;
406           case MERGE_CHANNEL_AVERAGE:
407             /* Weights based on sample metadata. Per channel since not
408              * all files are guaranteed to have the same channels. */
409             const int total_samples = channel_total_samples[out_offset];
410             const float t = (float)layer.samples / (float)total_samples;
411
412             for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
413               out_pixels[out_offset] += t * pixels[offset];
414             }
415             break;
416         }
417       }
418     }
419   }
420
421   return true;
422 }
423
424 static bool save_output(const string &filepath,
425                         const ImageSpec &spec,
426                         const array<float> &pixels,
427                         string &error)
428 {
429   /* Write to temporary file path, so we merge images in place and don't
430    * risk destroying files when something goes wrong in file saving. */
431   string extension = OIIO::Filesystem::extension(filepath);
432   string unique_name = ".merge-tmp-" + OIIO::Filesystem::unique_path();
433   string tmp_filepath = filepath + unique_name + extension;
434   unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
435
436   if (!out) {
437     error = "Failed to open temporary file " + tmp_filepath + " for writing";
438     return false;
439   }
440
441   /* Open temporary file and write image buffers. */
442   if (!out->open(tmp_filepath, spec)) {
443     error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror();
444     return false;
445   }
446
447   bool ok = true;
448   if (!out->write_image(TypeDesc::FLOAT, pixels.data())) {
449     error = "Failed to write to file " + tmp_filepath + ": " + out->geterror();
450     ok = false;
451   }
452
453   if (!out->close()) {
454     error = "Failed to save to file " + tmp_filepath + ": " + out->geterror();
455     ok = false;
456   }
457
458   out.reset();
459
460   /* Copy temporary file to outputput filepath. */
461   string rename_error;
462   if (ok && !OIIO::Filesystem::rename(tmp_filepath, filepath, rename_error)) {
463     error = "Failed to move merged image to " + filepath + ": " + rename_error;
464     ok = false;
465   }
466
467   if (!ok) {
468     OIIO::Filesystem::remove(tmp_filepath);
469   }
470
471   return ok;
472 }
473
474 /* Image Merger */
475
476 ImageMerger::ImageMerger()
477 {
478 }
479
480 bool ImageMerger::run()
481 {
482   if (input.empty()) {
483     error = "No input file paths specified.";
484     return false;
485   }
486   if (output.empty()) {
487     error = "No output file path specified.";
488     return false;
489   }
490
491   /* Open images and verify they have matching layout. */
492   vector<MergeImage> images;
493   if (!open_images(input, images, error)) {
494     return false;
495   }
496
497   /* Merge metadata and setup channels and offsets. */
498   ImageSpec out_spec;
499   vector<int> channel_total_samples;
500   merge_channels_metadata(images, out_spec, channel_total_samples);
501
502   /* Merge pixels. */
503   array<float> out_pixels;
504   if (!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) {
505     return false;
506   }
507
508   /* We don't need input anymore at this point, and will possibly
509    * overwrite the same file. */
510   images.clear();
511
512   /* Save output file. */
513   return save_output(output, out_spec, out_pixels, error);
514 }
515
516 CCL_NAMESPACE_END