/src/openexr/src/lib/OpenEXR/ImfCompositeDeepScanLine.cpp
Line | Count | Source |
1 | | // |
2 | | // SPDX-License-Identifier: BSD-3-Clause |
3 | | // Copyright (c) Weta Digital, Ltd and Contributors to the OpenEXR Project. |
4 | | // |
5 | | |
6 | | #include "ImfCompositeDeepScanLine.h" |
7 | | #include "IlmThreadPool.h" |
8 | | #include "ImfChannelList.h" |
9 | | #include "ImfDeepCompositing.h" |
10 | | #include "ImfDeepFrameBuffer.h" |
11 | | #include "ImfDeepScanLineInputFile.h" |
12 | | #include "ImfDeepScanLineInputPart.h" |
13 | | #include "ImfFrameBuffer.h" |
14 | | #include "ImfPixelType.h" |
15 | | |
16 | | #include <Iex.h> |
17 | | #include <stddef.h> |
18 | | #include <vector> |
19 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER |
20 | | |
21 | | using ILMTHREAD_NAMESPACE::Task; |
22 | | using ILMTHREAD_NAMESPACE::TaskGroup; |
23 | | using ILMTHREAD_NAMESPACE::ThreadPool; |
24 | | using IMATH_NAMESPACE::Box2i; |
25 | | using std::string; |
26 | | using std::vector; |
27 | | |
28 | | struct CompositeDeepScanLine::Data |
29 | | { |
30 | | public: |
31 | | vector<DeepScanLineInputFile*> _file; // array of files |
32 | | vector<DeepScanLineInputPart*> _part; // array of parts |
33 | | FrameBuffer _outputFrameBuffer; // output frame buffer provided |
34 | | bool _zback; // true if we are using zback (otherwise channel 1 = channel 0) |
35 | | vector<vector<float>> |
36 | | _channeldata; // pixel values, read from the input, one array per channel |
37 | | vector<int> _sampleCounts; // total per-pixel sample counts, |
38 | | Box2i _dataWindow; // data window of combined inputs |
39 | | DeepCompositing* _comp; // user-provided compositor |
40 | | vector<string> _channels; // names of channels that will be composited |
41 | | vector<int> |
42 | | _bufferMap; // entry _outputFrameBuffer[n].name() == _channels[ _bufferMap[n] ].name() |
43 | | |
44 | | void check_valid ( |
45 | | const Header& |
46 | | header); // check newly added part/file is OK; on first good call, set _zback/_dataWindow |
47 | | |
48 | | // |
49 | | // set up the given deep frame buffer to contain the required channels |
50 | | // resize counts and pointers to the width of _dataWindow |
51 | | // zero-out all counts, since the datawindow may be smaller than/not include this part |
52 | | // |
53 | | |
54 | | void handleDeepFrameBuffer ( |
55 | | DeepFrameBuffer& buf, |
56 | | vector<unsigned int>& counts, //per-pixel counts |
57 | | vector<vector<float*>>& |
58 | | pointers, //per-channel-per-pixel pointers to data |
59 | | const Header& header, |
60 | | int start, |
61 | | int end); |
62 | | |
63 | | Data (); |
64 | | }; |
65 | | |
66 | 635 | CompositeDeepScanLine::Data::Data () : _zback (false), _comp (NULL) |
67 | 635 | {} |
68 | | |
69 | 635 | CompositeDeepScanLine::CompositeDeepScanLine () : _Data (new Data) |
70 | 635 | {} |
71 | | |
72 | | CompositeDeepScanLine::~CompositeDeepScanLine () |
73 | 635 | { |
74 | 635 | delete _Data; |
75 | 635 | } |
76 | | |
77 | | void |
78 | | CompositeDeepScanLine::addSource (DeepScanLineInputPart* part) |
79 | 0 | { |
80 | 0 | _Data->check_valid (part->header ()); |
81 | 0 | _Data->_part.push_back (part); |
82 | 0 | } |
83 | | |
84 | | void |
85 | | CompositeDeepScanLine::addSource (DeepScanLineInputFile* file) |
86 | 635 | { |
87 | 635 | _Data->check_valid (file->header ()); |
88 | 635 | _Data->_file.push_back (file); |
89 | 635 | } |
90 | | |
91 | | int |
92 | | CompositeDeepScanLine::sources () const |
93 | 0 | { |
94 | 0 | return int (_Data->_part.size ()) + int (_Data->_file.size ()); |
95 | 0 | } |
96 | | |
97 | | void |
98 | | CompositeDeepScanLine::Data::check_valid (const Header& header) |
99 | 635 | { |
100 | | |
101 | 635 | bool has_z = false; |
102 | 635 | bool has_alpha = false; |
103 | | // check good channel names |
104 | 635 | for (ChannelList::ConstIterator i = header.channels ().begin (); |
105 | 8.36k | i != header.channels ().end (); |
106 | 7.72k | ++i) |
107 | 7.72k | { |
108 | 7.72k | std::string n (i.name ()); |
109 | 7.72k | if (n == "ZBack") { _zback = true; } |
110 | 7.61k | else if (n == "Z") { has_z = true; } |
111 | 7.02k | else if (n == "A") { has_alpha = true; } |
112 | 7.72k | } |
113 | | |
114 | 635 | if (!has_z) |
115 | 45 | { |
116 | 45 | throw IEX_NAMESPACE::ArgExc ( |
117 | 45 | "Deep data provided to CompositeDeepScanLine is missing a Z channel"); |
118 | 45 | } |
119 | | |
120 | 590 | if (!has_alpha) |
121 | 9 | { |
122 | 9 | throw IEX_NAMESPACE::ArgExc ( |
123 | 9 | "Deep data provided to CompositeDeepScanLine is missing an alpha channel"); |
124 | 9 | } |
125 | | |
126 | 581 | if (_part.size () == 0 && _file.size () == 0) |
127 | 581 | { |
128 | | // first in - update and return |
129 | | |
130 | 581 | _dataWindow = header.dataWindow (); |
131 | | |
132 | 581 | return; |
133 | 581 | } |
134 | | |
135 | 0 | const Header* const match_header = _part.size () > 0 ? &_part[0]->header () |
136 | 0 | : &_file[0]->header (); |
137 | | |
138 | | // check the sizes match |
139 | 0 | if (match_header->displayWindow () != header.displayWindow ()) |
140 | 0 | { |
141 | 0 | throw IEX_NAMESPACE::ArgExc ( |
142 | 0 | "Deep data provided to CompositeDeepScanLine has a different displayWindow to previously provided data"); |
143 | 0 | } |
144 | | |
145 | 0 | _dataWindow.extendBy (header.dataWindow ()); |
146 | 0 | } |
147 | | void |
148 | | CompositeDeepScanLine::Data::handleDeepFrameBuffer ( |
149 | | DeepFrameBuffer& buf, |
150 | | std::vector<unsigned int>& counts, |
151 | | vector<std::vector<float*>>& pointers, |
152 | | const Header& header, |
153 | | int start, |
154 | | int end) |
155 | 1.22k | { |
156 | 1.22k | ptrdiff_t width = _dataWindow.size ().x + 1; |
157 | 1.22k | size_t pixelcount = width * (end - start + 1); |
158 | 1.22k | pointers.resize (_channels.size ()); |
159 | 1.22k | counts.resize (pixelcount); |
160 | 1.22k | buf.insertSampleCountSlice (Slice ( |
161 | 1.22k | OPENEXR_IMF_INTERNAL_NAMESPACE::UINT, |
162 | 1.22k | (char*) (&counts[0] - _dataWindow.min.x - start * width), |
163 | 1.22k | sizeof (unsigned int), |
164 | 1.22k | sizeof (unsigned int) * width)); |
165 | | |
166 | 1.22k | pointers[0].resize (pixelcount); |
167 | 1.22k | buf.insert ( |
168 | 1.22k | "Z", |
169 | 1.22k | DeepSlice ( |
170 | 1.22k | OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
171 | 1.22k | (char*) (&pointers[0][0] - _dataWindow.min.x - start * width), |
172 | 1.22k | sizeof (float*), |
173 | 1.22k | sizeof (float*) * width, |
174 | 1.22k | sizeof (float))); |
175 | | |
176 | 1.22k | if (_zback) |
177 | 574 | { |
178 | 574 | pointers[1].resize (pixelcount); |
179 | 574 | buf.insert ( |
180 | 574 | "ZBack", |
181 | 574 | DeepSlice ( |
182 | 574 | OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
183 | 574 | (char*) (&pointers[1][0] - _dataWindow.min.x - start * width), |
184 | 574 | sizeof (float*), |
185 | 574 | sizeof (float*) * width, |
186 | 574 | sizeof (float))); |
187 | 574 | } |
188 | | |
189 | 1.22k | pointers[2].resize (pixelcount); |
190 | 1.22k | buf.insert ( |
191 | 1.22k | "A", |
192 | 1.22k | DeepSlice ( |
193 | 1.22k | OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
194 | 1.22k | (char*) (&pointers[2][0] - _dataWindow.min.x - start * width), |
195 | 1.22k | sizeof (float*), |
196 | 1.22k | sizeof (float*) * width, |
197 | 1.22k | sizeof (float))); |
198 | | |
199 | 1.22k | size_t i = 0; |
200 | 1.22k | for (FrameBuffer::ConstIterator qt = _outputFrameBuffer.begin (); |
201 | 4.00k | qt != _outputFrameBuffer.end (); |
202 | 2.77k | qt++) |
203 | 2.77k | { |
204 | 2.77k | int channel_in_source = _bufferMap[i]; |
205 | 2.77k | if (channel_in_source > 2) |
206 | 2.32k | { |
207 | | // not dealt with yet (0,1,2 previously inserted) |
208 | 2.32k | pointers[channel_in_source].resize (pixelcount); |
209 | 2.32k | buf.insert ( |
210 | 2.32k | qt.name (), |
211 | 2.32k | DeepSlice ( |
212 | 2.32k | OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
213 | 2.32k | (char*) (&pointers[channel_in_source][0] - |
214 | 2.32k | _dataWindow.min.x - start * width), |
215 | 2.32k | sizeof (float*), |
216 | 2.32k | sizeof (float*) * width, |
217 | 2.32k | sizeof (float))); |
218 | 2.32k | } |
219 | | |
220 | 2.77k | i++; |
221 | 2.77k | } |
222 | 1.22k | } |
223 | | |
224 | | void |
225 | | CompositeDeepScanLine::setCompositing (DeepCompositing* c) |
226 | 0 | { |
227 | 0 | _Data->_comp = c; |
228 | 0 | } |
229 | | |
230 | | const IMATH_NAMESPACE::Box2i& |
231 | | CompositeDeepScanLine::dataWindow () const |
232 | 0 | { |
233 | 0 | return _Data->_dataWindow; |
234 | 0 | } |
235 | | |
236 | | void |
237 | | CompositeDeepScanLine::setFrameBuffer (const FrameBuffer& fr) |
238 | 1.15k | { |
239 | | |
240 | | // |
241 | | // count channels; build map between channels in frame buffer |
242 | | // and channels in internal buffers |
243 | | // |
244 | | |
245 | 1.15k | _Data->_channels.resize (3); |
246 | 1.15k | _Data->_channels[0] = "Z"; |
247 | 1.15k | _Data->_channels[1] = _Data->_zback ? "ZBack" : "Z"; |
248 | 1.15k | _Data->_channels[2] = "A"; |
249 | 1.15k | _Data->_bufferMap.resize (0); |
250 | | |
251 | 3.29k | for (FrameBuffer::ConstIterator q = fr.begin (); q != fr.end (); q++) |
252 | 2.13k | { |
253 | | |
254 | | // |
255 | | // Frame buffer must have xSampling and ySampling set to 1 |
256 | | // (Sampling in FrameBuffers must match sampling in file, |
257 | | // and Header::sanityCheck enforces sampling in deep files is 1) |
258 | | // |
259 | | |
260 | 2.13k | if (q.slice ().xSampling != 1 || q.slice ().ySampling != 1) |
261 | 0 | { |
262 | 0 | THROW ( |
263 | 0 | IEX_NAMESPACE::ArgExc, |
264 | 0 | "X and/or y subsampling factors " |
265 | 0 | "of \"" |
266 | 0 | << q.name () |
267 | 0 | << "\" channel in framebuffer " |
268 | 0 | "are not 1"); |
269 | 0 | } |
270 | | |
271 | 2.13k | string name (q.name ()); |
272 | 2.13k | if (name == "ZBack") { _Data->_bufferMap.push_back (1); } |
273 | 2.13k | else if (name == "Z") { _Data->_bufferMap.push_back (0); } |
274 | 2.13k | else if (name == "A") { _Data->_bufferMap.push_back (2); } |
275 | 2.08k | else |
276 | 2.08k | { |
277 | 2.08k | _Data->_bufferMap.push_back ( |
278 | 2.08k | static_cast<int> (_Data->_channels.size ())); |
279 | 2.08k | _Data->_channels.push_back (name); |
280 | 2.08k | } |
281 | 2.13k | } |
282 | | |
283 | 1.15k | _Data->_outputFrameBuffer = fr; |
284 | 1.15k | } |
285 | | |
286 | | namespace |
287 | | { |
288 | | |
289 | | class LineCompositeTask : public Task |
290 | | { |
291 | | public: |
292 | | LineCompositeTask ( |
293 | | TaskGroup* group, |
294 | | CompositeDeepScanLine::Data* data, |
295 | | int y, |
296 | | int start, |
297 | | vector<const char*>* names, |
298 | | vector<vector<vector<float*>>>* pointers, |
299 | | vector<unsigned int>* total_sizes, |
300 | | vector<unsigned int>* num_sources) |
301 | 671 | : Task (group) |
302 | 671 | , _Data (data) |
303 | 671 | , _y (y) |
304 | 671 | , _start (start) |
305 | 671 | , _names (names) |
306 | 671 | , _pointers (pointers) |
307 | 671 | , _total_sizes (total_sizes) |
308 | 671 | , _num_sources (num_sources) |
309 | 671 | {} |
310 | | |
311 | 0 | virtual ~LineCompositeTask () {} |
312 | | |
313 | | virtual void execute (); |
314 | | CompositeDeepScanLine::Data* _Data; |
315 | | int _y; |
316 | | int _start; |
317 | | vector<const char*>* _names; |
318 | | vector<vector<vector<float*>>>* _pointers; |
319 | | vector<unsigned int>* _total_sizes; |
320 | | vector<unsigned int>* _num_sources; |
321 | | }; |
322 | | |
323 | | void |
324 | | composite_line ( |
325 | | int y, |
326 | | int start, |
327 | | CompositeDeepScanLine::Data* _Data, |
328 | | vector<const char*>& names, |
329 | | const vector<vector<vector<float*>>>& pointers, |
330 | | const vector<unsigned int>& total_sizes, |
331 | | const vector<unsigned int>& num_sources) |
332 | 671 | { |
333 | 671 | vector<float> output_pixel (names.size ()); //the pixel we'll output to |
334 | 671 | vector<const float*> inputs (names.size ()); |
335 | 671 | DeepCompositing d; // fallback compositing engine |
336 | 671 | DeepCompositing* comp = _Data->_comp ? _Data->_comp : &d; |
337 | | |
338 | 671 | int pixel = |
339 | 671 | (y - start) * (_Data->_dataWindow.max.x + 1 - _Data->_dataWindow.min.x); |
340 | | |
341 | 360k | for (int x = _Data->_dataWindow.min.x; x <= _Data->_dataWindow.max.x; x++) |
342 | 359k | { |
343 | | // set inputs[] to point to the first sample of the first part of each channel |
344 | | // if there's a zback, set all channel independently... |
345 | | |
346 | 359k | if (_Data->_zback) |
347 | 358k | { |
348 | | |
349 | 1.43M | for (size_t channel = 0; channel < names.size (); channel++) |
350 | 1.07M | { |
351 | 1.07M | inputs[channel] = pointers[0][channel][pixel]; |
352 | 1.07M | } |
353 | 358k | } |
354 | 492 | else |
355 | 492 | { |
356 | | |
357 | | // otherwise, set 0 and 1 to point to Z |
358 | | |
359 | 492 | inputs[0] = pointers[0][0][pixel]; |
360 | 492 | inputs[1] = pointers[0][0][pixel]; |
361 | 1.26k | for (size_t channel = 2; channel < names.size (); channel++) |
362 | 769 | { |
363 | 769 | inputs[channel] = pointers[0][channel][pixel]; |
364 | 769 | } |
365 | 492 | } |
366 | 359k | comp->composite_pixel ( |
367 | 359k | &output_pixel[0], |
368 | 359k | &inputs[0], |
369 | 359k | &names[0], |
370 | 359k | static_cast<int> (names.size ()), |
371 | 359k | total_sizes[pixel], |
372 | 359k | num_sources[pixel]); |
373 | | |
374 | 359k | size_t channel_number = 0; |
375 | | |
376 | | // |
377 | | // write out composited value into internal frame buffer |
378 | | // |
379 | 359k | for (FrameBuffer::Iterator it = _Data->_outputFrameBuffer.begin (); |
380 | 719k | it != _Data->_outputFrameBuffer.end (); |
381 | 359k | it++) |
382 | 359k | { |
383 | | |
384 | 359k | float value = output_pixel |
385 | 359k | [_Data->_bufferMap[channel_number]]; // value to write |
386 | 359k | intptr_t base = reinterpret_cast<intptr_t> (it.slice ().base); |
387 | | |
388 | | // cast to half float if necessary |
389 | 359k | if (it.slice ().type == OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT) |
390 | 0 | { |
391 | 0 | float* ptr = reinterpret_cast<float*> ( |
392 | 0 | base + y * it.slice ().yStride + x * it.slice ().xStride); |
393 | 0 | *ptr = value; |
394 | 0 | } |
395 | 359k | else if (it.slice ().type == HALF) |
396 | 359k | { |
397 | 359k | half* ptr = reinterpret_cast<half*> ( |
398 | 359k | base + y * it.slice ().yStride + x * it.slice ().xStride); |
399 | 359k | *ptr = half (value); |
400 | 359k | } |
401 | | |
402 | 359k | channel_number++; |
403 | 359k | } |
404 | | |
405 | 359k | pixel++; |
406 | | |
407 | 359k | } // next pixel on row |
408 | 671 | } |
409 | | |
410 | | void |
411 | | LineCompositeTask::execute () |
412 | 671 | { |
413 | 671 | composite_line ( |
414 | 671 | _y, _start, _Data, *_names, *_pointers, *_total_sizes, *_num_sources); |
415 | 671 | } |
416 | | |
417 | | } // namespace |
418 | | |
419 | | namespace |
420 | | { |
421 | | int64_t maximumSampleCount = 0; |
422 | | } |
423 | | |
424 | | void |
425 | | CompositeDeepScanLine::setMaximumSampleCount (int64_t c) |
426 | 0 | { |
427 | 0 | maximumSampleCount = c; |
428 | 0 | } |
429 | | |
430 | | int64_t |
431 | | CompositeDeepScanLine::getMaximumSampleCount () |
432 | 0 | { |
433 | 0 | return maximumSampleCount; |
434 | 0 | } |
435 | | |
436 | | void |
437 | | CompositeDeepScanLine::readPixels (int start, int end) |
438 | 1.22k | { |
439 | 1.22k | size_t parts = |
440 | 1.22k | _Data->_file.size () + _Data->_part.size (); // total of files+parts |
441 | | |
442 | 1.22k | vector<DeepFrameBuffer> framebuffers (parts); |
443 | 1.22k | vector<vector<unsigned int>> counts (parts); |
444 | | |
445 | | // |
446 | | // for each part, a pointer to an array of channels |
447 | | // |
448 | 1.22k | vector<vector<vector<float*>>> pointers (parts); |
449 | 1.22k | vector<const Header*> headers (parts); |
450 | | |
451 | 1.22k | { |
452 | 1.22k | size_t i; |
453 | 2.45k | for (i = 0; i < _Data->_file.size (); i++) |
454 | 1.22k | { |
455 | 1.22k | headers[i] = &_Data->_file[i]->header (); |
456 | 1.22k | } |
457 | | |
458 | 1.22k | for (size_t j = 0; j < _Data->_part.size (); j++) |
459 | 0 | { |
460 | 0 | headers[i + j] = &_Data->_part[j]->header (); |
461 | 0 | } |
462 | 1.22k | } |
463 | | |
464 | 2.45k | for (size_t i = 0; i < parts; i++) |
465 | 1.22k | { |
466 | 1.22k | _Data->handleDeepFrameBuffer ( |
467 | 1.22k | framebuffers[i], counts[i], pointers[i], *headers[i], start, end); |
468 | 1.22k | } |
469 | | |
470 | | // |
471 | | // set frame buffers and read scanlines from all parts |
472 | | // TODO what happens if SCANLINE not in data window? |
473 | | // |
474 | | |
475 | 1.22k | { |
476 | 1.22k | size_t i = 0; |
477 | 2.45k | for (i = 0; i < _Data->_file.size (); i++) |
478 | 1.22k | { |
479 | 1.22k | _Data->_file[i]->setFrameBuffer (framebuffers[i]); |
480 | 1.22k | _Data->_file[i]->readPixelSampleCounts (start, end); |
481 | 1.22k | } |
482 | 1.22k | for (size_t j = 0; j < _Data->_part.size (); j++) |
483 | 0 | { |
484 | 0 | _Data->_part[j]->setFrameBuffer (framebuffers[i + j]); |
485 | 0 | _Data->_part[j]->readPixelSampleCounts (start, end); |
486 | 0 | } |
487 | 1.22k | } |
488 | | |
489 | | // |
490 | | // total width |
491 | | // |
492 | | |
493 | 1.22k | size_t total_width = _Data->_dataWindow.size ().x + 1; |
494 | 1.22k | size_t total_pixels = total_width * (end - start + 1); |
495 | 1.22k | vector<unsigned int> total_sizes (total_pixels); |
496 | 1.22k | vector<unsigned int> num_sources ( |
497 | 1.22k | total_pixels); //number of parts with non-zero sample count |
498 | | |
499 | 1.22k | int64_t overall_sample_count = |
500 | 1.22k | 0; // sum of all samples in all images between start and end |
501 | | |
502 | | // |
503 | | // accumulate pixel counts |
504 | | // |
505 | 360k | for (size_t ptr = 0; ptr < total_pixels; ptr++) |
506 | 359k | { |
507 | 359k | total_sizes[ptr] = 0; |
508 | 359k | num_sources[ptr] = 0; |
509 | 718k | for (size_t j = 0; j < parts; j++) |
510 | 359k | { |
511 | 359k | if (total_sizes[ptr] > std::numeric_limits<unsigned int>::max() - counts[j][ptr]) |
512 | 0 | throw IEX_NAMESPACE::ArgExc ( |
513 | 0 | "Cannot composite scanline: pixel cannot have more than UINT_MAX samples"); |
514 | | |
515 | 359k | total_sizes[ptr] += counts[j][ptr]; |
516 | 359k | if (counts[j][ptr] > 0) num_sources[ptr]++; |
517 | 359k | } |
518 | 359k | overall_sample_count += total_sizes[ptr]; |
519 | 359k | } |
520 | | |
521 | 1.22k | if (maximumSampleCount > 0 && overall_sample_count > maximumSampleCount) |
522 | 0 | { |
523 | 0 | throw IEX_NAMESPACE::ArgExc ( |
524 | 0 | "Cannot composite scanline: total sample count on scanline exceeds " |
525 | 0 | "limit set by CompositeDeepScanLine::setMaximumSampleCount()"); |
526 | 0 | } |
527 | | |
528 | | // |
529 | | // allocate arrays for pixel data |
530 | | // samples array accessed as in pixels[channel][sample] |
531 | | // |
532 | | |
533 | 1.22k | vector<vector<float>> samples (_Data->_channels.size ()); |
534 | | |
535 | 3.56k | for (size_t channel = 0; channel < _Data->_channels.size (); channel++) |
536 | 2.34k | { |
537 | 2.34k | if (channel != 1 || _Data->_zback) |
538 | 2.14k | { |
539 | 2.14k | samples[channel].resize (overall_sample_count); |
540 | 2.14k | } |
541 | 2.34k | } |
542 | | |
543 | 3.56k | for (size_t channel = 0; channel < samples.size (); channel++) |
544 | 2.34k | { |
545 | | |
546 | 2.34k | if (channel != 1 || _Data->_zback) |
547 | 2.14k | { |
548 | | |
549 | 2.14k | samples[channel].resize (overall_sample_count); |
550 | | |
551 | | // |
552 | | // allocate pointers for channel data |
553 | | // |
554 | | |
555 | 2.14k | int64_t offset = 0; |
556 | | |
557 | 1.08M | for (size_t pixel = 0; pixel < total_pixels; pixel++) |
558 | 1.07M | { |
559 | 1.07M | for (size_t part = 0; |
560 | 1.08M | part < parts && offset < overall_sample_count; |
561 | 1.07M | part++) |
562 | 3.31k | { |
563 | 3.31k | pointers[part][channel][pixel] = &samples[channel][offset]; |
564 | 3.31k | offset += counts[part][pixel]; |
565 | 3.31k | } |
566 | 1.07M | } |
567 | 2.14k | } |
568 | 2.34k | } |
569 | | |
570 | | // |
571 | | // read data |
572 | | // |
573 | | |
574 | 1.89k | for (size_t i = 0; i < _Data->_file.size (); i++) |
575 | 673 | { |
576 | 673 | _Data->_file[i]->readPixels (start, end); |
577 | 673 | } |
578 | 1.22k | for (size_t j = 0; j < _Data->_part.size (); j++) |
579 | 0 | { |
580 | 0 | _Data->_part[j]->readPixels (start, end); |
581 | 0 | } |
582 | | |
583 | | // |
584 | | // composite pixels and write back to framebuffer |
585 | | // |
586 | | |
587 | | // turn vector of strings into array of char * |
588 | | // and make sure 'ZBack' channel is correct |
589 | 1.22k | vector<const char*> names (_Data->_channels.size ()); |
590 | 3.55k | for (size_t i = 0; i < names.size (); i++) |
591 | 2.33k | { |
592 | 2.33k | names[i] = _Data->_channels[i].c_str (); |
593 | 2.33k | } |
594 | | |
595 | 1.22k | if (!_Data->_zback) |
596 | 192 | names[1] = names[0]; // no zback channel, so make it point to z |
597 | | |
598 | 1.22k | TaskGroup g; |
599 | 1.89k | for (int y = start; y <= end; y++) |
600 | 671 | { |
601 | 671 | ThreadPool::addGlobalTask (new LineCompositeTask ( |
602 | 671 | &g, |
603 | 671 | _Data, |
604 | 671 | y, |
605 | 671 | start, |
606 | 671 | &names, |
607 | 671 | &pointers, |
608 | 671 | &total_sizes, |
609 | 671 | &num_sources)); |
610 | 671 | } //next row |
611 | 1.22k | } |
612 | | |
613 | | const FrameBuffer& |
614 | | CompositeDeepScanLine::frameBuffer () const |
615 | 3 | { |
616 | 3 | return _Data->_outputFrameBuffer; |
617 | 3 | } |
618 | | |
619 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT |