Coverage Report

Created: 2023-12-08 06:53

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