Nori
|
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 */