PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/OpenEXR/IlmImf/ImfScanLineInputFile.cpp

https://gitlab.com/seranth/FreeImage
C++ | 1702 lines | 1088 code | 311 blank | 303 comment | 144 complexity | a186b06cd22d37ff33efeadff6a79008 MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
  4. // Digital Ltd. LLC
  5. //
  6. // All rights reserved.
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. // * Redistributions of source code must retain the above copyright
  12. // notice, this list of conditions and the following disclaimer.
  13. // * Redistributions in binary form must reproduce the above
  14. // copyright notice, this list of conditions and the following disclaimer
  15. // in the documentation and/or other materials provided with the
  16. // distribution.
  17. // * Neither the name of Industrial Light & Magic nor the names of
  18. // its contributors may be used to endorse or promote products derived
  19. // from this software without specific prior written permission.
  20. //
  21. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. //
  33. ///////////////////////////////////////////////////////////////////////////
  34. //-----------------------------------------------------------------------------
  35. //
  36. // class ScanLineInputFile
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include "ImfScanLineInputFile.h"
  40. #include "ImfChannelList.h"
  41. #include "ImfMisc.h"
  42. #include "ImfStdIO.h"
  43. #include "ImfCompressor.h"
  44. #include "ImathBox.h"
  45. #include "ImathFun.h"
  46. #include <ImfXdr.h>
  47. #include <ImfConvert.h>
  48. #include <ImfThreading.h>
  49. #include <ImfPartType.h>
  50. #include "IlmThreadPool.h"
  51. #include "IlmThreadSemaphore.h"
  52. #include "IlmThreadMutex.h"
  53. #include "Iex.h"
  54. #include "ImfVersion.h"
  55. #include "ImfOptimizedPixelReading.h"
  56. #include "ImfNamespace.h"
  57. #include "ImfStandardAttributes.h"
  58. #include <algorithm>
  59. #include <string>
  60. #include <vector>
  61. #include <assert.h>
  62. #include <cstring>
  63. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
  64. using IMATH_NAMESPACE::Box2i;
  65. using IMATH_NAMESPACE::divp;
  66. using IMATH_NAMESPACE::modp;
  67. using std::string;
  68. using std::vector;
  69. using std::ifstream;
  70. using std::min;
  71. using std::max;
  72. using std::sort;
  73. using ILMTHREAD_NAMESPACE::Mutex;
  74. using ILMTHREAD_NAMESPACE::Lock;
  75. using ILMTHREAD_NAMESPACE::Semaphore;
  76. using ILMTHREAD_NAMESPACE::Task;
  77. using ILMTHREAD_NAMESPACE::TaskGroup;
  78. using ILMTHREAD_NAMESPACE::ThreadPool;
  79. namespace {
  80. struct InSliceInfo
  81. {
  82. PixelType typeInFrameBuffer;
  83. PixelType typeInFile;
  84. char * base;
  85. size_t xStride;
  86. size_t yStride;
  87. int xSampling;
  88. int ySampling;
  89. bool fill;
  90. bool skip;
  91. double fillValue;
  92. InSliceInfo (PixelType typeInFrameBuffer = HALF,
  93. PixelType typeInFile = HALF,
  94. char *base = 0,
  95. size_t xStride = 0,
  96. size_t yStride = 0,
  97. int xSampling = 1,
  98. int ySampling = 1,
  99. bool fill = false,
  100. bool skip = false,
  101. double fillValue = 0.0);
  102. };
  103. InSliceInfo::InSliceInfo (PixelType tifb,
  104. PixelType tifl,
  105. char *b,
  106. size_t xs, size_t ys,
  107. int xsm, int ysm,
  108. bool f, bool s,
  109. double fv)
  110. :
  111. typeInFrameBuffer (tifb),
  112. typeInFile (tifl),
  113. base (b),
  114. xStride (xs),
  115. yStride (ys),
  116. xSampling (xsm),
  117. ySampling (ysm),
  118. fill (f),
  119. skip (s),
  120. fillValue (fv)
  121. {
  122. // empty
  123. }
  124. struct LineBuffer
  125. {
  126. const char * uncompressedData;
  127. char * buffer;
  128. int dataSize;
  129. int minY;
  130. int maxY;
  131. Compressor * compressor;
  132. Compressor::Format format;
  133. int number;
  134. bool hasException;
  135. string exception;
  136. LineBuffer (Compressor * const comp);
  137. ~LineBuffer ();
  138. inline void wait () {_sem.wait();}
  139. inline void post () {_sem.post();}
  140. private:
  141. Semaphore _sem;
  142. };
  143. LineBuffer::LineBuffer (Compressor *comp):
  144. uncompressedData (0),
  145. buffer (0),
  146. dataSize (0),
  147. compressor (comp),
  148. format (defaultFormat(compressor)),
  149. number (-1),
  150. hasException (false),
  151. exception (),
  152. _sem (1)
  153. {
  154. // empty
  155. }
  156. LineBuffer::~LineBuffer ()
  157. {
  158. delete compressor;
  159. }
  160. /// helper struct used to detect the order that the channels are stored
  161. struct sliceOptimizationData
  162. {
  163. const char * base; ///< pointer to pixel data
  164. bool fill; ///< is this channel being filled with constant, instead of read?
  165. half fillValue; ///< if filling, the value to use
  166. size_t offset; ///< position this channel will be in the read buffer, accounting for previous channels, as well as their type
  167. PixelType type; ///< type of channel
  168. size_t xStride; ///< x-stride of channel in buffer (must be set to cause channels to interleave)
  169. size_t yStride; ///< y-stride of channel in buffer (must be same in all channels, else order will change, which is bad)
  170. int xSampling; ///< channel x sampling
  171. int ySampling; ///< channel y sampling
  172. /// we need to keep the list sorted in the order they'll be written to memory
  173. bool operator<(const sliceOptimizationData& other ) const
  174. {
  175. return base < other.base;
  176. }
  177. };
  178. } // namespace
  179. struct ScanLineInputFile::Data: public Mutex
  180. {
  181. Header header; // the image header
  182. int version; // file's version
  183. FrameBuffer frameBuffer; // framebuffer to write into
  184. LineOrder lineOrder; // order of the scanlines in file
  185. int minX; // data window's min x coord
  186. int maxX; // data window's max x coord
  187. int minY; // data window's min y coord
  188. int maxY; // data window's max x coord
  189. vector<Int64> lineOffsets; // stores offsets in file for
  190. // each line
  191. bool fileIsComplete; // True if no scanlines are missing
  192. // in the file
  193. int nextLineBufferMinY; // minimum y of the next linebuffer
  194. vector<size_t> bytesPerLine; // combined size of a line over all
  195. // channels
  196. vector<size_t> offsetInLineBuffer; // offset for each scanline in its
  197. // linebuffer
  198. vector<InSliceInfo> slices; // info about channels in file
  199. vector<LineBuffer*> lineBuffers; // each holds one line buffer
  200. int linesInBuffer; // number of scanlines each buffer
  201. // holds
  202. size_t lineBufferSize; // size of the line buffer
  203. int partNumber; // part number
  204. bool memoryMapped; // if the stream is memory mapped
  205. OptimizationMode optimizationMode; // optimizibility of the input file
  206. vector<sliceOptimizationData> optimizationData; ///< channel ordering for optimized reading
  207. Data (int numThreads);
  208. ~Data ();
  209. inline LineBuffer * getLineBuffer (int number); // hash function from line
  210. // buffer indices into our
  211. // vector of line buffers
  212. };
  213. ScanLineInputFile::Data::Data (int numThreads):
  214. partNumber(-1),
  215. memoryMapped(false)
  216. {
  217. //
  218. // We need at least one lineBuffer, but if threading is used,
  219. // to keep n threads busy we need 2*n lineBuffers
  220. //
  221. lineBuffers.resize (max (1, 2 * numThreads));
  222. }
  223. ScanLineInputFile::Data::~Data ()
  224. {
  225. for (size_t i = 0; i < lineBuffers.size(); i++)
  226. delete lineBuffers[i];
  227. }
  228. inline LineBuffer *
  229. ScanLineInputFile::Data::getLineBuffer (int lineBufferNumber)
  230. {
  231. return lineBuffers[lineBufferNumber % lineBuffers.size()];
  232. }
  233. namespace {
  234. void
  235. reconstructLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
  236. LineOrder lineOrder,
  237. vector<Int64> &lineOffsets)
  238. {
  239. Int64 position = is.tellg();
  240. try
  241. {
  242. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  243. {
  244. Int64 lineOffset = is.tellg();
  245. int y;
  246. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y);
  247. int dataSize;
  248. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, dataSize);
  249. Xdr::skip <StreamIO> (is, dataSize);
  250. if (lineOrder == INCREASING_Y)
  251. lineOffsets[i] = lineOffset;
  252. else
  253. lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
  254. }
  255. }
  256. catch (...)
  257. {
  258. //
  259. // Suppress all exceptions. This functions is
  260. // called only to reconstruct the line offset
  261. // table for incomplete files, and exceptions
  262. // are likely.
  263. //
  264. }
  265. is.clear();
  266. is.seekg (position);
  267. }
  268. void
  269. readLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
  270. LineOrder lineOrder,
  271. vector<Int64> &lineOffsets,
  272. bool &complete)
  273. {
  274. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  275. {
  276. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, lineOffsets[i]);
  277. }
  278. complete = true;
  279. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  280. {
  281. if (lineOffsets[i] <= 0)
  282. {
  283. //
  284. // Invalid data in the line offset table mean that
  285. // the file is probably incomplete (the table is
  286. // the last thing written to the file). Either
  287. // some process is still busy writing the file,
  288. // or writing the file was aborted.
  289. //
  290. // We should still be able to read the existing
  291. // parts of the file. In order to do this, we
  292. // have to make a sequential scan over the scan
  293. // line data to reconstruct the line offset table.
  294. //
  295. complete = false;
  296. reconstructLineOffsets (is, lineOrder, lineOffsets);
  297. break;
  298. }
  299. }
  300. }
  301. void
  302. readPixelData (InputStreamMutex *streamData,
  303. ScanLineInputFile::Data *ifd,
  304. int minY,
  305. char *&buffer,
  306. int &dataSize)
  307. {
  308. //
  309. // Read a single line buffer from the input file.
  310. //
  311. // If the input file is not memory-mapped, we copy the pixel data into
  312. // into the array pointed to by buffer. If the file is memory-mapped,
  313. // then we change where buffer points to instead of writing into the
  314. // array (hence buffer needs to be a reference to a char *).
  315. //
  316. int lineBufferNumber = (minY - ifd->minY) / ifd->linesInBuffer;
  317. Int64 lineOffset = ifd->lineOffsets[lineBufferNumber];
  318. if (lineOffset == 0)
  319. THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
  320. //
  321. // Seek to the start of the scan line in the file,
  322. // if necessary.
  323. //
  324. if ( !isMultiPart(ifd->version) )
  325. {
  326. if (ifd->nextLineBufferMinY != minY)
  327. streamData->is->seekg (lineOffset);
  328. }
  329. else
  330. {
  331. //
  332. // In a multi-part file, the file pointer may have been moved by
  333. // other parts, so we have to ask tellg() where we are.
  334. //
  335. if (streamData->is->tellg() != ifd->lineOffsets[lineBufferNumber])
  336. streamData->is->seekg (lineOffset);
  337. }
  338. //
  339. // Read the data block's header.
  340. //
  341. int yInFile;
  342. //
  343. // Read the part number when we are dealing with a multi-part file.
  344. //
  345. if (isMultiPart(ifd->version))
  346. {
  347. int partNumber;
  348. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
  349. if (partNumber != ifd->partNumber)
  350. {
  351. THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
  352. << ", should be " << ifd->partNumber << ".");
  353. }
  354. }
  355. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, yInFile);
  356. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, dataSize);
  357. if (yInFile != minY)
  358. throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
  359. if (dataSize > (int) ifd->lineBufferSize)
  360. throw IEX_NAMESPACE::InputExc ("Unexpected data block length.");
  361. //
  362. // Read the pixel data.
  363. //
  364. if (streamData->is->isMemoryMapped ())
  365. buffer = streamData->is->readMemoryMapped (dataSize);
  366. else
  367. streamData->is->read (buffer, dataSize);
  368. //
  369. // Keep track of which scan line is the next one in
  370. // the file, so that we can avoid redundant seekg()
  371. // operations (seekg() can be fairly expensive).
  372. //
  373. if (ifd->lineOrder == INCREASING_Y)
  374. ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
  375. else
  376. ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
  377. }
  378. //
  379. // A LineBufferTask encapsulates the task uncompressing a set of
  380. // scanlines (line buffer) and copying them into the frame buffer.
  381. //
  382. class LineBufferTask : public Task
  383. {
  384. public:
  385. LineBufferTask (TaskGroup *group,
  386. ScanLineInputFile::Data *ifd,
  387. LineBuffer *lineBuffer,
  388. int scanLineMin,
  389. int scanLineMax,
  390. OptimizationMode optimizationMode);
  391. virtual ~LineBufferTask ();
  392. virtual void execute ();
  393. private:
  394. ScanLineInputFile::Data * _ifd;
  395. LineBuffer * _lineBuffer;
  396. int _scanLineMin;
  397. int _scanLineMax;
  398. OptimizationMode _optimizationMode;
  399. };
  400. LineBufferTask::LineBufferTask
  401. (TaskGroup *group,
  402. ScanLineInputFile::Data *ifd,
  403. LineBuffer *lineBuffer,
  404. int scanLineMin,
  405. int scanLineMax,OptimizationMode optimizationMode)
  406. :
  407. Task (group),
  408. _ifd (ifd),
  409. _lineBuffer (lineBuffer),
  410. _scanLineMin (scanLineMin),
  411. _scanLineMax (scanLineMax),
  412. _optimizationMode(optimizationMode)
  413. {
  414. // empty
  415. }
  416. LineBufferTask::~LineBufferTask ()
  417. {
  418. //
  419. // Signal that the line buffer is now free
  420. //
  421. _lineBuffer->post ();
  422. }
  423. void
  424. LineBufferTask::execute ()
  425. {
  426. try
  427. {
  428. //
  429. // Uncompress the data, if necessary
  430. //
  431. if (_lineBuffer->uncompressedData == 0)
  432. {
  433. int uncompressedSize = 0;
  434. int maxY = min (_lineBuffer->maxY, _ifd->maxY);
  435. for (int i = _lineBuffer->minY - _ifd->minY;
  436. i <= maxY - _ifd->minY;
  437. ++i)
  438. {
  439. uncompressedSize += (int) _ifd->bytesPerLine[i];
  440. }
  441. if (_lineBuffer->compressor &&
  442. _lineBuffer->dataSize < uncompressedSize)
  443. {
  444. _lineBuffer->format = _lineBuffer->compressor->format();
  445. _lineBuffer->dataSize = _lineBuffer->compressor->uncompress
  446. (_lineBuffer->buffer,
  447. _lineBuffer->dataSize,
  448. _lineBuffer->minY,
  449. _lineBuffer->uncompressedData);
  450. }
  451. else
  452. {
  453. //
  454. // If the line is uncompressed, it's in XDR format,
  455. // regardless of the compressor's output format.
  456. //
  457. _lineBuffer->format = Compressor::XDR;
  458. _lineBuffer->uncompressedData = _lineBuffer->buffer;
  459. }
  460. }
  461. int yStart, yStop, dy;
  462. if (_ifd->lineOrder == INCREASING_Y)
  463. {
  464. yStart = _scanLineMin;
  465. yStop = _scanLineMax + 1;
  466. dy = 1;
  467. }
  468. else
  469. {
  470. yStart = _scanLineMax;
  471. yStop = _scanLineMin - 1;
  472. dy = -1;
  473. }
  474. for (int y = yStart; y != yStop; y += dy)
  475. {
  476. //
  477. // Convert one scan line's worth of pixel data back
  478. // from the machine-independent representation, and
  479. // store the result in the frame buffer.
  480. //
  481. const char *readPtr = _lineBuffer->uncompressedData +
  482. _ifd->offsetInLineBuffer[y - _ifd->minY];
  483. //
  484. // Iterate over all image channels.
  485. //
  486. for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
  487. {
  488. //
  489. // Test if scan line y of this channel contains any data
  490. // (the scan line contains data only if y % ySampling == 0).
  491. //
  492. const InSliceInfo &slice = _ifd->slices[i];
  493. if (modp (y, slice.ySampling) != 0)
  494. continue;
  495. //
  496. // Find the x coordinates of the leftmost and rightmost
  497. // sampled pixels (i.e. pixels within the data window
  498. // for which x % xSampling == 0).
  499. //
  500. int dMinX = divp (_ifd->minX, slice.xSampling);
  501. int dMaxX = divp (_ifd->maxX, slice.xSampling);
  502. //
  503. // Fill the frame buffer with pixel data.
  504. //
  505. if (slice.skip)
  506. {
  507. //
  508. // The file contains data for this channel, but
  509. // the frame buffer contains no slice for this channel.
  510. //
  511. skipChannel (readPtr, slice.typeInFile, dMaxX - dMinX + 1);
  512. }
  513. else
  514. {
  515. //
  516. // The frame buffer contains a slice for this channel.
  517. //
  518. char *linePtr = slice.base +
  519. divp (y, slice.ySampling) *
  520. slice.yStride;
  521. char *writePtr = linePtr + dMinX * slice.xStride;
  522. char *endPtr = linePtr + dMaxX * slice.xStride;
  523. copyIntoFrameBuffer (readPtr, writePtr, endPtr,
  524. slice.xStride, slice.fill,
  525. slice.fillValue, _lineBuffer->format,
  526. slice.typeInFrameBuffer,
  527. slice.typeInFile);
  528. }
  529. }
  530. }
  531. }
  532. catch (std::exception &e)
  533. {
  534. if (!_lineBuffer->hasException)
  535. {
  536. _lineBuffer->exception = e.what();
  537. _lineBuffer->hasException = true;
  538. }
  539. }
  540. catch (...)
  541. {
  542. if (!_lineBuffer->hasException)
  543. {
  544. _lineBuffer->exception = "unrecognized exception";
  545. _lineBuffer->hasException = true;
  546. }
  547. }
  548. }
  549. #ifdef IMF_HAVE_SSE2
  550. //
  551. // IIF format is more restricted than a perfectly generic one,
  552. // so it is possible to perform some optimizations.
  553. //
  554. class LineBufferTaskIIF : public Task
  555. {
  556. public:
  557. LineBufferTaskIIF (TaskGroup *group,
  558. ScanLineInputFile::Data *ifd,
  559. LineBuffer *lineBuffer,
  560. int scanLineMin,
  561. int scanLineMax,
  562. OptimizationMode optimizationMode);
  563. virtual ~LineBufferTaskIIF ();
  564. virtual void execute ();
  565. template<typename TYPE>
  566. void getWritePointer (int y,
  567. unsigned short*& pOutWritePointerRight,
  568. size_t& outPixelsToCopySSE,
  569. size_t& outPixelsToCopyNormal,int bank=0) const;
  570. template<typename TYPE>
  571. void getWritePointerStereo (int y,
  572. unsigned short*& outWritePointerRight,
  573. unsigned short*& outWritePointerLeft,
  574. size_t& outPixelsToCopySSE,
  575. size_t& outPixelsToCopyNormal) const;
  576. private:
  577. ScanLineInputFile::Data * _ifd;
  578. LineBuffer * _lineBuffer;
  579. int _scanLineMin;
  580. int _scanLineMax;
  581. OptimizationMode _optimizationMode;
  582. };
  583. LineBufferTaskIIF::LineBufferTaskIIF
  584. (TaskGroup *group,
  585. ScanLineInputFile::Data *ifd,
  586. LineBuffer *lineBuffer,
  587. int scanLineMin,
  588. int scanLineMax,
  589. OptimizationMode optimizationMode
  590. )
  591. :
  592. Task (group),
  593. _ifd (ifd),
  594. _lineBuffer (lineBuffer),
  595. _scanLineMin (scanLineMin),
  596. _scanLineMax (scanLineMax),
  597. _optimizationMode (optimizationMode)
  598. {
  599. /*
  600. //
  601. // indicates the optimised path has been taken
  602. //
  603. static bool could_optimise=false;
  604. if(could_optimise==false)
  605. {
  606. std::cerr << " optimised path\n";
  607. could_optimise=true;
  608. }
  609. */
  610. }
  611. LineBufferTaskIIF::~LineBufferTaskIIF ()
  612. {
  613. //
  614. // Signal that the line buffer is now free
  615. //
  616. _lineBuffer->post ();
  617. }
  618. // Return 0 if we are to skip because of sampling
  619. // channelBank is 0 for the first group of channels, 1 for the second
  620. template<typename TYPE>
  621. void LineBufferTaskIIF::getWritePointer
  622. (int y,
  623. unsigned short*& outWritePointerRight,
  624. size_t& outPixelsToCopySSE,
  625. size_t& outPixelsToCopyNormal,
  626. int channelBank
  627. ) const
  628. {
  629. // Channels are saved alphabetically, so the order is B G R.
  630. // The last slice (R) will give us the location of our write pointer.
  631. // The only slice that we support skipping is alpha, i.e. the first one.
  632. // This does not impact the write pointer or the pixels to copy at all.
  633. size_t nbSlicesInBank = _ifd->optimizationData.size();
  634. int sizeOfSingleValue = sizeof(TYPE);
  635. if(_ifd->optimizationData.size()>4)
  636. {
  637. // there are two banks - we only copy one at once
  638. nbSlicesInBank/=2;
  639. }
  640. size_t firstChannel = 0;
  641. if(channelBank==1)
  642. {
  643. firstChannel = _ifd->optimizationData.size()/2;
  644. }
  645. sliceOptimizationData& firstSlice = _ifd->optimizationData[firstChannel];
  646. if (modp (y, firstSlice.ySampling) != 0)
  647. {
  648. outPixelsToCopySSE = 0;
  649. outPixelsToCopyNormal = 0;
  650. outWritePointerRight = 0;
  651. }
  652. const char* linePtr1 = firstSlice.base +
  653. divp (y, firstSlice.ySampling) *
  654. firstSlice.yStride;
  655. int dMinX1 = divp (_ifd->minX, firstSlice.xSampling);
  656. int dMaxX1 = divp (_ifd->maxX, firstSlice.xSampling);
  657. // Construct the writePtr so that we start writing at
  658. // linePtr + Min offset in the line.
  659. outWritePointerRight = (unsigned short*)(linePtr1 +
  660. dMinX1 * firstSlice.xStride );
  661. size_t bytesToCopy = ((linePtr1 + dMaxX1 * firstSlice.xStride ) -
  662. (linePtr1 + dMinX1 * firstSlice.xStride )) + 2;
  663. size_t shortsToCopy = bytesToCopy / sizeOfSingleValue;
  664. size_t pixelsToCopy = (shortsToCopy / nbSlicesInBank ) + 1;
  665. // We only support writing to SSE if we have no pixels to copy normally
  666. outPixelsToCopySSE = pixelsToCopy / 8;
  667. outPixelsToCopyNormal = pixelsToCopy % 8;
  668. }
  669. template<typename TYPE>
  670. void LineBufferTaskIIF::getWritePointerStereo
  671. (int y,
  672. unsigned short*& outWritePointerRight,
  673. unsigned short*& outWritePointerLeft,
  674. size_t& outPixelsToCopySSE,
  675. size_t& outPixelsToCopyNormal) const
  676. {
  677. getWritePointer<TYPE>(y,outWritePointerRight,outPixelsToCopySSE,outPixelsToCopyNormal,0);
  678. if(outWritePointerRight)
  679. {
  680. getWritePointer<TYPE>(y,outWritePointerLeft,outPixelsToCopySSE,outPixelsToCopyNormal,1);
  681. }
  682. }
  683. void
  684. LineBufferTaskIIF::execute()
  685. {
  686. try
  687. {
  688. //
  689. // Uncompress the data, if necessary
  690. //
  691. if (_lineBuffer->uncompressedData == 0)
  692. {
  693. int uncompressedSize = 0;
  694. int maxY = min (_lineBuffer->maxY, _ifd->maxY);
  695. for (int i = _lineBuffer->minY - _ifd->minY;
  696. i <= maxY - _ifd->minY;
  697. ++i)
  698. {
  699. uncompressedSize += (int) _ifd->bytesPerLine[i];
  700. }
  701. if (_lineBuffer->compressor &&
  702. _lineBuffer->dataSize < uncompressedSize)
  703. {
  704. _lineBuffer->format = _lineBuffer->compressor->format();
  705. _lineBuffer->dataSize =
  706. _lineBuffer->compressor->uncompress (_lineBuffer->buffer,
  707. _lineBuffer->dataSize,
  708. _lineBuffer->minY,
  709. _lineBuffer->uncompressedData);
  710. }
  711. else
  712. {
  713. //
  714. // If the line is uncompressed, it's in XDR format,
  715. // regardless of the compressor's output format.
  716. //
  717. _lineBuffer->format = Compressor::XDR;
  718. _lineBuffer->uncompressedData = _lineBuffer->buffer;
  719. }
  720. }
  721. int yStart, yStop, dy;
  722. if (_ifd->lineOrder == INCREASING_Y)
  723. {
  724. yStart = _scanLineMin;
  725. yStop = _scanLineMax + 1;
  726. dy = 1;
  727. }
  728. else
  729. {
  730. yStart = _scanLineMax;
  731. yStop = _scanLineMin - 1;
  732. dy = -1;
  733. }
  734. for (int y = yStart; y != yStop; y += dy)
  735. {
  736. if (modp (y, _optimizationMode._ySampling) != 0)
  737. continue;
  738. //
  739. // Convert one scan line's worth of pixel data back
  740. // from the machine-independent representation, and
  741. // store the result in the frame buffer.
  742. //
  743. // Set the readPtr to read at the start of uncompressedData
  744. // but with an offet based on calculated array.
  745. // _ifd->offsetInLineBuffer contains offsets based on which
  746. // line we are currently processing.
  747. // Stride will be taken into consideration later.
  748. const char* readPtr = _lineBuffer->uncompressedData +
  749. _ifd->offsetInLineBuffer[y - _ifd->minY];
  750. size_t pixelsToCopySSE = 0;
  751. size_t pixelsToCopyNormal = 0;
  752. unsigned short* writePtrLeft = 0;
  753. unsigned short* writePtrRight = 0;
  754. size_t channels = _ifd->optimizationData.size();
  755. if(channels>4)
  756. {
  757. getWritePointerStereo<half>(y, writePtrRight, writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  758. }
  759. else
  760. {
  761. getWritePointer<half>(y, writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  762. }
  763. if (writePtrRight == 0 && pixelsToCopySSE == 0 && pixelsToCopyNormal == 0)
  764. {
  765. continue;
  766. }
  767. //
  768. // support reading up to eight channels
  769. //
  770. unsigned short* readPointers[8];
  771. for (size_t i = 0; i < channels ; ++i)
  772. {
  773. readPointers[i] = (unsigned short*)readPtr + (_ifd->optimizationData[i].offset * (pixelsToCopySSE * 8 + pixelsToCopyNormal));
  774. }
  775. //RGB only
  776. if(channels==3 || channels == 6 )
  777. {
  778. optimizedWriteToRGB(readPointers[0], readPointers[1], readPointers[2], writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  779. //stereo RGB
  780. if( channels == 6)
  781. {
  782. optimizedWriteToRGB(readPointers[3], readPointers[4], readPointers[5], writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  783. }
  784. //RGBA
  785. }else if(channels==4 || channels==8)
  786. {
  787. if(_ifd->optimizationData[3].fill)
  788. {
  789. optimizedWriteToRGBAFillA(readPointers[0], readPointers[1], readPointers[2], _ifd->optimizationData[3].fillValue.bits() , writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  790. }else{
  791. optimizedWriteToRGBA(readPointers[0], readPointers[1], readPointers[2], readPointers[3] , writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  792. }
  793. //stereo RGBA
  794. if( channels == 8)
  795. {
  796. if(_ifd->optimizationData[7].fill)
  797. {
  798. optimizedWriteToRGBAFillA(readPointers[4], readPointers[5], readPointers[6], _ifd->optimizationData[7].fillValue.bits() , writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  799. }else{
  800. optimizedWriteToRGBA(readPointers[4], readPointers[5], readPointers[6], readPointers[7] , writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  801. }
  802. }
  803. }
  804. else {
  805. throw(IEX_NAMESPACE::LogicExc("IIF mode called with incorrect channel pattern"));
  806. }
  807. // If we are in NO_OPTIMIZATION mode, this class will never
  808. // get instantiated, so no need to check for it and duplicate
  809. // the code.
  810. }
  811. }
  812. catch (std::exception &e)
  813. {
  814. if (!_lineBuffer->hasException)
  815. {
  816. _lineBuffer->exception = e.what();
  817. _lineBuffer->hasException = true;
  818. }
  819. }
  820. catch (...)
  821. {
  822. if (!_lineBuffer->hasException)
  823. {
  824. _lineBuffer->exception = "unrecognized exception";
  825. _lineBuffer->hasException = true;
  826. }
  827. }
  828. }
  829. #endif
  830. Task *
  831. newLineBufferTask (TaskGroup *group,
  832. InputStreamMutex *streamData,
  833. ScanLineInputFile::Data *ifd,
  834. int number,
  835. int scanLineMin,
  836. int scanLineMax,
  837. OptimizationMode optimizationMode)
  838. {
  839. //
  840. // Wait for a line buffer to become available, fill the line
  841. // buffer with raw data from the file if necessary, and create
  842. // a new LineBufferTask whose execute() method will uncompress
  843. // the contents of the buffer and copy the pixels into the
  844. // frame buffer.
  845. //
  846. LineBuffer *lineBuffer = ifd->getLineBuffer (number);
  847. try
  848. {
  849. lineBuffer->wait ();
  850. if (lineBuffer->number != number)
  851. {
  852. lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
  853. lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
  854. lineBuffer->number = number;
  855. lineBuffer->uncompressedData = 0;
  856. readPixelData (streamData, ifd, lineBuffer->minY,
  857. lineBuffer->buffer,
  858. lineBuffer->dataSize);
  859. }
  860. }
  861. catch (std::exception &e)
  862. {
  863. if (!lineBuffer->hasException)
  864. {
  865. lineBuffer->exception = e.what();
  866. lineBuffer->hasException = true;
  867. }
  868. lineBuffer->number = -1;
  869. lineBuffer->post();
  870. throw;
  871. }
  872. catch (...)
  873. {
  874. //
  875. // Reading from the file caused an exception.
  876. // Signal that the line buffer is free, and
  877. // re-throw the exception.
  878. //
  879. lineBuffer->exception = "unrecognized exception";
  880. lineBuffer->hasException = true;
  881. lineBuffer->number = -1;
  882. lineBuffer->post();
  883. throw;
  884. }
  885. scanLineMin = max (lineBuffer->minY, scanLineMin);
  886. scanLineMax = min (lineBuffer->maxY, scanLineMax);
  887. Task* retTask = 0;
  888. #ifdef IMF_HAVE_SSE2
  889. if (optimizationMode._optimizable)
  890. {
  891. retTask = new LineBufferTaskIIF (group, ifd, lineBuffer,
  892. scanLineMin, scanLineMax,
  893. optimizationMode);
  894. }
  895. else
  896. #endif
  897. {
  898. retTask = new LineBufferTask (group, ifd, lineBuffer,
  899. scanLineMin, scanLineMax,
  900. optimizationMode);
  901. }
  902. return retTask;
  903. }
  904. } // namespace
  905. void ScanLineInputFile::initialize(const Header& header)
  906. {
  907. try
  908. {
  909. _data->header = header;
  910. _data->lineOrder = _data->header.lineOrder();
  911. const Box2i &dataWindow = _data->header.dataWindow();
  912. _data->minX = dataWindow.min.x;
  913. _data->maxX = dataWindow.max.x;
  914. _data->minY = dataWindow.min.y;
  915. _data->maxY = dataWindow.max.y;
  916. size_t maxBytesPerLine = bytesPerLineTable (_data->header,
  917. _data->bytesPerLine);
  918. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  919. {
  920. _data->lineBuffers[i] = new LineBuffer (newCompressor
  921. (_data->header.compression(),
  922. maxBytesPerLine,
  923. _data->header));
  924. }
  925. _data->linesInBuffer =
  926. numLinesInBuffer (_data->lineBuffers[0]->compressor);
  927. _data->lineBufferSize = maxBytesPerLine * _data->linesInBuffer;
  928. if (!_streamData->is->isMemoryMapped())
  929. {
  930. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  931. {
  932. _data->lineBuffers[i]->buffer = (char *) EXRAllocAligned(_data->lineBufferSize*sizeof(char),16);
  933. }
  934. }
  935. _data->nextLineBufferMinY = _data->minY - 1;
  936. offsetInLineBufferTable (_data->bytesPerLine,
  937. _data->linesInBuffer,
  938. _data->offsetInLineBuffer);
  939. int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
  940. _data->linesInBuffer) / _data->linesInBuffer;
  941. _data->lineOffsets.resize (lineOffsetSize);
  942. }
  943. catch (...)
  944. {
  945. delete _data;
  946. _data=NULL;
  947. throw;
  948. }
  949. }
  950. ScanLineInputFile::ScanLineInputFile(InputPartData* part)
  951. {
  952. if (part->header.type() != SCANLINEIMAGE)
  953. throw IEX_NAMESPACE::ArgExc("Can't build a ScanLineInputFile from a type-mismatched part.");
  954. _data = new Data(part->numThreads);
  955. _streamData = part->mutex;
  956. _data->memoryMapped = _streamData->is->isMemoryMapped();
  957. _data->version = part->version;
  958. initialize(part->header);
  959. _data->lineOffsets = part->chunkOffsets;
  960. _data->partNumber = part->partNumber;
  961. //
  962. // (TODO) change this code later.
  963. // The completeness of the file should be detected in MultiPartInputFile.
  964. //
  965. _data->fileIsComplete = true;
  966. }
  967. ScanLineInputFile::ScanLineInputFile
  968. (const Header &header,
  969. OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
  970. int numThreads)
  971. :
  972. _data (new Data (numThreads)),
  973. _streamData (new InputStreamMutex())
  974. {
  975. _streamData->is = is;
  976. _data->memoryMapped = is->isMemoryMapped();
  977. initialize(header);
  978. //
  979. // (TODO) this is nasty - we need a better way of working out what type of file has been used.
  980. // in any case I believe this constructor only gets used with single part files
  981. // and 'version' currently only tracks multipart state, so setting to 0 (not multipart) works for us
  982. //
  983. _data->version=0;
  984. readLineOffsets (*_streamData->is,
  985. _data->lineOrder,
  986. _data->lineOffsets,
  987. _data->fileIsComplete);
  988. }
  989. ScanLineInputFile::~ScanLineInputFile ()
  990. {
  991. if (!_data->memoryMapped)
  992. {
  993. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  994. {
  995. EXRFreeAligned(_data->lineBuffers[i]->buffer);
  996. }
  997. }
  998. //
  999. // ScanLineInputFile should never delete the stream,
  1000. // because it does not own the stream.
  1001. // We just delete the Mutex here.
  1002. //
  1003. if (_data->partNumber == -1)
  1004. delete _streamData;
  1005. delete _data;
  1006. }
  1007. const char *
  1008. ScanLineInputFile::fileName () const
  1009. {
  1010. return _streamData->is->fileName();
  1011. }
  1012. const Header &
  1013. ScanLineInputFile::header () const
  1014. {
  1015. return _data->header;
  1016. }
  1017. int
  1018. ScanLineInputFile::version () const
  1019. {
  1020. return _data->version;
  1021. }
  1022. namespace
  1023. {
  1024. // returns the optimization state for the given arrangement of frame bufers
  1025. // this assumes:
  1026. // both the file and framebuffer are half float data
  1027. // both the file and framebuffer have xSampling and ySampling=1
  1028. // entries in optData are sorted into their interleave order (i.e. by base address)
  1029. // These tests are done by SetFrameBuffer as it is building optData
  1030. //
  1031. OptimizationMode
  1032. detectOptimizationMode (const vector<sliceOptimizationData>& optData)
  1033. {
  1034. OptimizationMode w;
  1035. // need to be compiled with SSE optimisations: if not, just returns false
  1036. #if IMF_HAVE_SSE2
  1037. // only handle reading 3,4,6 or 8 channels
  1038. switch(optData.size())
  1039. {
  1040. case 3 : break;
  1041. case 4 : break;
  1042. case 6 : break;
  1043. case 8 : break;
  1044. default :
  1045. return w;
  1046. }
  1047. //
  1048. // the point at which data switches between the primary and secondary bank
  1049. //
  1050. size_t bankSize = optData.size()>4 ? optData.size()/2 : optData.size();
  1051. for(size_t i=0;i<optData.size();i++)
  1052. {
  1053. const sliceOptimizationData& data = optData[i];
  1054. // can't fill anything other than channel 3 or channel 7
  1055. if(data.fill)
  1056. {
  1057. if(i!=3 && i!=7)
  1058. {
  1059. return w;
  1060. }
  1061. }
  1062. // cannot have gaps in the channel layout, so the stride must be (number of channels written in the bank)*2
  1063. if(data.xStride !=bankSize*2)
  1064. {
  1065. return w;
  1066. }
  1067. // each bank of channels must be channel interleaved: each channel base pointer must be (previous channel+2)
  1068. // this also means channel sampling pattern must be consistent, as must yStride
  1069. if(i!=0 && i!=bankSize)
  1070. {
  1071. if(data.base!=optData[i-1].base+2)
  1072. {
  1073. return w;
  1074. }
  1075. }
  1076. if(i!=0)
  1077. {
  1078. if(data.yStride!=optData[i-1].yStride)
  1079. {
  1080. return w;
  1081. }
  1082. }
  1083. }
  1084. w._ySampling=optData[0].ySampling;
  1085. w._optimizable=true;
  1086. #endif
  1087. return w;
  1088. }
  1089. } // Anonymous namespace
  1090. void
  1091. ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
  1092. {
  1093. Lock lock (*_streamData);
  1094. const ChannelList &channels = _data->header.channels();
  1095. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  1096. j != frameBuffer.end();
  1097. ++j)
  1098. {
  1099. ChannelList::ConstIterator i = channels.find (j.name());
  1100. if (i == channels.end())
  1101. continue;
  1102. if (i.channel().xSampling != j.slice().xSampling ||
  1103. i.channel().ySampling != j.slice().ySampling)
  1104. THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
  1105. "of \"" << i.name() << "\" channel "
  1106. "of input file \"" << fileName() << "\" are "
  1107. "not compatible with the frame buffer's "
  1108. "subsampling factors.");
  1109. }
  1110. // optimization is possible if this is a little endian system
  1111. // and both inputs and outputs are half floats
  1112. //
  1113. bool optimizationPossible = true;
  1114. if (!GLOBAL_SYSTEM_LITTLE_ENDIAN)
  1115. {
  1116. optimizationPossible =false;
  1117. }
  1118. vector<sliceOptimizationData> optData;
  1119. //
  1120. // Initialize the slice table for readPixels().
  1121. //
  1122. vector<InSliceInfo> slices;
  1123. ChannelList::ConstIterator i = channels.begin();
  1124. // current offset of channel: pixel data starts at offset*width into the
  1125. // decompressed scanline buffer
  1126. size_t offset = 0;
  1127. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  1128. j != frameBuffer.end();
  1129. ++j)
  1130. {
  1131. while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
  1132. {
  1133. //
  1134. // Channel i is present in the file but not
  1135. // in the frame buffer; data for channel i
  1136. // will be skipped during readPixels().
  1137. //
  1138. slices.push_back (InSliceInfo (i.channel().type,
  1139. i.channel().type,
  1140. 0, // base
  1141. 0, // xStride
  1142. 0, // yStride
  1143. i.channel().xSampling,
  1144. i.channel().ySampling,
  1145. false, // fill
  1146. true, // skip
  1147. 0.0)); // fillValue
  1148. switch(i.channel().type)
  1149. {
  1150. case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
  1151. offset++;
  1152. break;
  1153. case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
  1154. offset+=2;
  1155. break;
  1156. case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
  1157. offset+=2;
  1158. break;
  1159. }
  1160. ++i;
  1161. }
  1162. bool fill = false;
  1163. if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
  1164. {
  1165. //
  1166. // Channel i is present in the frame buffer, but not in the file.
  1167. // In the frame buffer, slice j will be filled with a default value.
  1168. //
  1169. fill = true;
  1170. }
  1171. slices.push_back (InSliceInfo (j.slice().type,
  1172. fill? j.slice().type:
  1173. i.channel().type,
  1174. j.slice().base,
  1175. j.slice().xStride,
  1176. j.slice().yStride,
  1177. j.slice().xSampling,
  1178. j.slice().ySampling,
  1179. fill,
  1180. false, // skip
  1181. j.slice().fillValue));
  1182. if(!fill && i.channel().type!=OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
  1183. {
  1184. optimizationPossible = false;
  1185. }
  1186. if(j.slice().type != OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
  1187. {
  1188. optimizationPossible = false;
  1189. }
  1190. if(j.slice().xSampling!=1 || j.slice().ySampling!=1)
  1191. {
  1192. optimizationPossible = false;
  1193. }
  1194. if(optimizationPossible)
  1195. {
  1196. sliceOptimizationData dat;
  1197. dat.base = j.slice().base;
  1198. dat.fill = fill;
  1199. dat.fillValue = j.slice().fillValue;
  1200. dat.offset = offset;
  1201. dat.xStride = j.slice().xStride;
  1202. dat.yStride = j.slice().yStride;
  1203. dat.xSampling = j.slice().xSampling;
  1204. dat.ySampling = j.slice().ySampling;
  1205. optData.push_back(dat);
  1206. }
  1207. if(!fill)
  1208. {
  1209. switch(i.channel().type)
  1210. {
  1211. case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
  1212. offset++;
  1213. break;
  1214. case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
  1215. offset+=2;
  1216. break;
  1217. case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
  1218. offset+=2;
  1219. break;
  1220. }
  1221. }
  1222. if (i != channels.end() && !fill)
  1223. ++i;
  1224. }
  1225. if(optimizationPossible)
  1226. {
  1227. //
  1228. // check optimisibility
  1229. // based on channel ordering and fill channel positions
  1230. //
  1231. sort(optData.begin(),optData.end());
  1232. _data->optimizationMode = detectOptimizationMode(optData);
  1233. }
  1234. if(!optimizationPossible || _data->optimizationMode._optimizable==false)
  1235. {
  1236. optData = vector<sliceOptimizationData>();
  1237. _data->optimizationMode._optimizable=false;
  1238. }
  1239. //
  1240. // Store the new frame buffer.
  1241. //
  1242. _data->frameBuffer = frameBuffer;
  1243. _data->slices = slices;
  1244. _data->optimizationData = optData;
  1245. }
  1246. const FrameBuffer &
  1247. ScanLineInputFile::frameBuffer () const
  1248. {
  1249. Lock lock (*_streamData);
  1250. return _data->frameBuffer;
  1251. }
  1252. bool
  1253. ScanLineInputFile::isComplete () const
  1254. {
  1255. return _data->fileIsComplete;
  1256. }
  1257. bool ScanLineInputFile::isOptimizationEnabled() const
  1258. {
  1259. if (_data->slices.size() == 0)
  1260. throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
  1261. "as pixel data destination.");
  1262. return _data->optimizationMode._optimizable;
  1263. }
  1264. void
  1265. ScanLineInputFile::readPixels (int scanLine1, int scanLine2)
  1266. {
  1267. try
  1268. {
  1269. Lock lock (*_streamData);
  1270. if (_data->slices.size() == 0)
  1271. throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
  1272. "as pixel data destination.");
  1273. int scanLineMin = min (scanLine1, scanLine2);
  1274. int scanLineMax = max (scanLine1, scanLine2);
  1275. if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
  1276. throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
  1277. "the image file's data window.");
  1278. //
  1279. // We impose a numbering scheme on the lineBuffers where the first
  1280. // scanline is contained in lineBuffer 1.
  1281. //
  1282. // Determine the first and last lineBuffer numbers in this scanline
  1283. // range. We always attempt to read the scanlines in the order that
  1284. // they are stored in the file.
  1285. //
  1286. int start, stop, dl;
  1287. if (_data->lineOrder == INCREASING_Y)
  1288. {
  1289. start = (scanLineMin - _data->minY) / _data->linesInBuffer;
  1290. stop = (scanLineMax - _data->minY) / _data->linesInBuffer + 1;
  1291. dl = 1;
  1292. }
  1293. else
  1294. {
  1295. start = (scanLineMax - _data->minY) / _data->linesInBuffer;
  1296. stop = (scanLineMin - _data->minY) / _data->linesInBuffer - 1;
  1297. dl = -1;
  1298. }
  1299. //
  1300. // Create a task group for all line buffer tasks. When the
  1301. // task group goes out of scope, the destructor waits until
  1302. // all tasks are complete.
  1303. //
  1304. {
  1305. TaskGroup taskGroup;
  1306. //
  1307. // Add the line buffer tasks.
  1308. //
  1309. // The tasks will execute in the order that they are created
  1310. // because we lock the line buffers during construction and the
  1311. // constructors are called by the main thread. Hence, in order
  1312. // for a successive task to execute the previous task which
  1313. // used that line buffer must have completed already.
  1314. //
  1315. for (int l = start; l != stop; l += dl)
  1316. {
  1317. ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
  1318. _streamData,
  1319. _data, l,
  1320. scanLineMin,
  1321. scanLineMax,
  1322. _data->optimizationMode));
  1323. }
  1324. //
  1325. // finish all tasks
  1326. //
  1327. }
  1328. //
  1329. // Exeption handling:
  1330. //
  1331. // LineBufferTask::execute() may have encountered exceptions, but
  1332. // those exceptions occurred in another thread, not in the thread
  1333. // that is executing this call to ScanLineInputFile::readPixels().
  1334. // LineBufferTask::execute() has caught all exceptions and stored
  1335. // the exceptions' what() strings in the line buffers.
  1336. // Now we check if any line buffer contains a stored exception; if
  1337. // this is the case then we re-throw the exception in this thread.
  1338. // (It is possible that multiple line buffers contain stored
  1339. // exceptions. We re-throw the first exception we find and
  1340. // ignore all others.)
  1341. //
  1342. const string *exception = 0;
  1343. for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
  1344. {
  1345. LineBuffer *lineBuffer = _data->lineBuffers[i];
  1346. if (lineBuffer->hasException && !exception)
  1347. exception = &lineBuffer->exception;
  1348. lineBuffer->hasException = false;
  1349. }
  1350. if (exception)
  1351. throw IEX_NAMESPACE::IoExc (*exception);
  1352. }
  1353. catch (IEX_NAMESPACE::BaseExc &e)
  1354. {
  1355. REPLACE_EXC (e, "Error reading pixel data from image "
  1356. "file \"" << fileName() << "\". " << e);
  1357. throw;
  1358. }
  1359. }
  1360. void
  1361. ScanLineInputFile::readPixels (int scanLine)
  1362. {
  1363. readPixels (scanLine, scanLine);
  1364. }
  1365. void
  1366. ScanLineInputFile::rawPixelData (int firstScanLine,
  1367. const char *&pixelData,
  1368. int &pixelDataSize)
  1369. {
  1370. try
  1371. {
  1372. Lock lock (*_streamData);
  1373. if (firstScanLine < _data->minY || firstScanLine > _data->maxY)
  1374. {
  1375. throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
  1376. "the image file's data window.");
  1377. }
  1378. int minY = lineBufferMinY
  1379. (firstScanLine, _data->minY, _data->linesInBuffer);
  1380. readPixelData
  1381. (_streamData, _data, minY, _data->lineBuffers[0]->buffer, pixelDataSize);
  1382. pixelData = _data->lineBuffers[0]->buffer;
  1383. }
  1384. catch (IEX_NAMESPACE::BaseExc &e)
  1385. {
  1386. REPLACE_EXC (e, "Error reading pixel data from image "
  1387. "file \"" << fileName() << "\". " << e);
  1388. throw;
  1389. }
  1390. }
  1391. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT