167 lines
5.1 KiB
C++
167 lines
5.1 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* =======================================================================
|
|
This file contains classes for parallel rendering of "image blocks".
|
|
* ======================================================================= */
|
|
|
|
#pragma once
|
|
|
|
#include <nori/color.h>
|
|
#include <nori/vector.h>
|
|
#include <tbb/mutex.h>
|
|
|
|
#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<Color4f, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> {
|
|
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
|