/* This file is part of Nori, a simple educational ray tracer Copyright (c) 2015 by Wenzel Jakob Nori is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 3 as published by the Free Software Foundation. Nori is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* ======================================================================= This file contains classes for parallel rendering of "image blocks". * ======================================================================= */ #pragma once #include #include #include #define NORI_BLOCK_SIZE 32 /* Block size used for parallelization */ NORI_NAMESPACE_BEGIN /** * \brief Weighted pixel storage for a rectangular subregion of an image * * This class implements storage for a rectangular subregion of a * larger image that is being rendered. For each pixel, it records color * values along with a weight that specifies the accumulated influence of * nearby samples on the pixel (according to the used reconstruction filter). * * When rendering with filters, the samples in a rectangular * region will generally also contribute to pixels just outside of * this region. For that reason, this class also stores information about * a small border region around the rectangle, whose size depends on the * properties of the reconstruction filter. */ class ImageBlock : public Eigen::Array { public: /** * Create a new image block of the specified maximum size * \param size * Desired maximum size of the block * \param filter * Samples will be convolved with the image reconstruction * filter provided here. */ ImageBlock(const Vector2i &size, const ReconstructionFilter *filter); /// Release all memory ~ImageBlock(); /// Configure the offset of the block within the main image void setOffset(const Point2i &offset) { m_offset = offset; } /// Return the offset of the block within the main image inline const Point2i &getOffset() const { return m_offset; } /// Configure the size of the block within the main image void setSize(const Point2i &size) { m_size = size; } /// Return the size of the block within the main image inline const Vector2i &getSize() const { return m_size; } /// Return the border size in pixels inline int getBorderSize() const { return m_borderSize; } /** * \brief Turn the block into a proper bitmap * * This entails normalizing all pixels and discarding * the border region. */ Bitmap *toBitmap() const; /// Convert a bitmap into an image block void fromBitmap(const Bitmap &bitmap); /// Clear all contents void clear() { setConstant(Color4f()); } /// Record a sample with the given position and radiance value void put(const Point2f &pos, const Color3f &value); /** * \brief Merge another image block into this one * * During the merge operation, this function locks * the destination block using a mutex. */ void put(ImageBlock &b); /// Lock the image block (using an internal mutex) inline void lock() const { m_mutex.lock(); } /// Unlock the image block inline void unlock() const { m_mutex.unlock(); } /// Return a human-readable string summary std::string toString() const; protected: Point2i m_offset; Vector2i m_size; int m_borderSize = 0; float *m_filter = nullptr; float m_filterRadius = 0; float *m_weightsX = nullptr; float *m_weightsY = nullptr; float m_lookupFactor = 0; mutable tbb::mutex m_mutex; }; /** * \brief Spiraling block generator * * This class can be used to chop up an image into many small * rectangular blocks suitable for parallel rendering. The blocks * are ordered in spiraling pattern so that the center is * rendered first. */ class BlockGenerator { public: /** * \brief Create a block generator with * \param size * Size of the image that should be split into blocks * \param blockSize * Maximum size of the individual blocks */ BlockGenerator(const Vector2i &size, int blockSize); /** * \brief Return the next block to be rendered * * This function is thread-safe * * \return \c false if there were no more blocks */ bool next(ImageBlock &block); /// Return the total number of blocks int getBlockCount() const { return m_blocksLeft; } protected: enum EDirection { ERight = 0, EDown, ELeft, EUp }; Point2i m_block; Vector2i m_numBlocks; Vector2i m_size; int m_blockSize; int m_numSteps; int m_blocksLeft; int m_stepsLeft; int m_direction; tbb::mutex m_mutex; }; NORI_NAMESPACE_END