Nori

include/nori/block.h

Go to the documentation of this file.
00001 /*
00002     This file is part of Nori, a simple educational ray tracer
00003 
00004     Copyright (c) 2012 by Wenzel Jakob and Steve Marschner.
00005 
00006     Nori is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License Version 3
00008     as published by the Free Software Foundation.
00009 
00010     Nori is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program. If not, see <http://www.gnu.org/licenses/>.
00017 */
00018 
00019 /* =======================================================================
00020      This file contains classes for parallel rendering of "image blocks".
00021  * ======================================================================= */
00022 
00023 #if !defined(__PARALLEL_H)
00024 #define __PARALLEL_H
00025 
00026 #include <nori/color.h>
00027 #include <nori/vector.h>
00028 #include <QMutex>
00029 #include <QThread>
00030 #include <QElapsedTimer>
00031 
00032 #define NORI_BLOCK_SIZE 32 /* Block size used for parallelization */
00033 
00034 NORI_NAMESPACE_BEGIN
00035 
00036 /**
00037  * \brief Weighted pixel storage for a rectangular subregion of an image
00038  *
00039  * This class implements storage for a rectangular subregion of a
00040  * larger image that is being rendered. For each pixel, it records color
00041  * values along with a weight that specifies the accumulated influence of
00042  * nearby samples on the pixel (according to the used reconstruction filter).
00043  *
00044  * When rendering with filters, the samples in a rectangular
00045  * region will generally also contribute to pixels just outside of 
00046  * this region. For that reason, this class also stores information about
00047  * a small border region around the rectangle, whose size depends on the
00048  * properties of the reconstruction filter.
00049  */
00050 class ImageBlock : public Eigen::Array<Color4f, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> {
00051 public:
00052         /**
00053          * Create a new image block of the specified maximum size
00054          * \param size
00055          *     Desired maximum size of the block
00056          * \param filter
00057          *     Samples will be convolved with the image reconstruction
00058          *     filter provided here.
00059          */
00060         ImageBlock(const Vector2i &size, const ReconstructionFilter *filter);
00061         
00062         /// Release all memory
00063         ~ImageBlock();
00064         
00065         /// Configure the offset of the block within the main image
00066         void setOffset(const Point2i &offset) { m_offset = offset; }
00067 
00068         /// Return the offset of the block within the main image
00069         inline const Point2i &getOffset() const { return m_offset; }
00070         
00071         /// Configure the size of the block within the main image
00072         void setSize(const Point2i &size) { m_size = size; }
00073 
00074         /// Return the size of the block within the main image
00075         inline const Vector2i &getSize() const { return m_size; }
00076 
00077         /// Return the border size in pixels
00078         inline int getBorderSize() const { return m_borderSize; }
00079 
00080         /**
00081          * \brief Turn the block into a proper bitmap
00082          * 
00083          * This entails normalizing all pixels and discarding
00084          * the border region.
00085          */
00086         Bitmap *toBitmap() const;
00087 
00088         /// Clear all contents
00089         void clear() { setConstant(Color4f()); }
00090 
00091         /// Record a sample with the given position and radiance value
00092         void put(const Point2f &pos, const Color3f &value);
00093 
00094         /**
00095          * \brief Merge another image block into this one
00096          *
00097          * During the merge operation, this function locks 
00098          * the destination block using a mutex.
00099          */
00100         void put(ImageBlock &b);
00101 
00102         /// Lock the image block (using an internal mutex)
00103         inline void lock() const { m_mutex.lock(); }
00104         
00105         /// Unlock the image block
00106         inline void unlock() const { m_mutex.unlock(); }
00107 
00108         /// Return a human-readable string summary
00109         QString toString() const;
00110 protected:
00111         Point2i  m_offset;
00112         Vector2i m_size;
00113         int m_borderSize;
00114         float *m_filter, m_filterRadius;
00115         float *m_weightsX, *m_weightsY;
00116         float m_lookupFactor;
00117         mutable QMutex m_mutex;
00118 };
00119 
00120 /**
00121  * \brief Spiraling block generator
00122  *
00123  * This class can be used to chop up an image into many small
00124  * rectangular blocks suitable for parallel rendering. The blocks
00125  * are ordered in spiraling pattern so that the center is
00126  * rendered first.
00127  */
00128 class BlockGenerator {
00129 public:
00130         /**
00131          * \brief Create a block generator with
00132          * \param size
00133          *      Size of the image that should be split into blocks
00134          * \param blockSize
00135          *      Maximum size of the individual blocks
00136          */
00137         BlockGenerator(const Vector2i &size, int blockSize);
00138         
00139         /**
00140          * \brief Return the next block to be rendered
00141          *
00142          * This function is thread-safe
00143          *
00144          * \return \c false if there were no more blocks
00145          */
00146         bool next(ImageBlock &block);
00147 protected:
00148         enum EDirection { ERight = 0, EDown, ELeft, EUp };
00149 
00150         Point2i m_block;
00151         Vector2i m_numBlocks;
00152         Vector2i m_size;
00153         int m_blockSize;
00154         int m_numSteps;
00155         int m_blocksLeft;
00156         int m_stepsLeft;
00157         int m_direction;
00158         QMutex m_mutex;
00159         QElapsedTimer m_timer;
00160 };
00161 
00162 /**
00163  * \brief Render thread
00164  *
00165  * This class implements the main rendering logic, which consists of
00166  * fetching work from a scheduler (in the form of rectangular image
00167  * blocks to be rendered), processing it, and writing the output
00168  * to a target buffer.
00169  */
00170 class BlockRenderThread : public QThread {
00171 public:
00172         /**
00173          * \brief Create a new rendering thread that fetches blocks from
00174          * the specified block generator and writes output to a big
00175          * \ref ImageBlock instance that represents the entire image
00176          */
00177         BlockRenderThread(const Scene *scene, Sampler *sampler,
00178                 BlockGenerator *blockGenerator, ImageBlock *output);
00179 
00180         /// Release all memory
00181         virtual ~BlockRenderThread();
00182 
00183         /// Main rendering thread loop
00184         void run();
00185 private:
00186         const Scene *m_scene;
00187         BlockGenerator *m_blockGenerator;
00188         ImageBlock *m_output;
00189         Sampler *m_sampler;
00190 };
00191 
00192 NORI_NAMESPACE_END
00193 
00194 #endif /* __PARALLEL_H */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines