/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2011 by Wenzel Jakob and others.
Mitsuba 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.
Mitsuba 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 .
*/
#include
#include
#include
#include
MTS_NAMESPACE_BEGIN
class BlockRenderer : public WorkProcessor {
public:
BlockRenderer(int blockSize, int borderSize)
: m_blockSize(blockSize), m_borderSize(borderSize) {
}
BlockRenderer(Stream *stream, InstanceManager *manager) {
m_blockSize = stream->readInt();
m_borderSize = stream->readInt();
m_collectStatistics = stream->readBool();
}
ref createWorkUnit() const {
return new RectangularWorkUnit();
}
ref createWorkResult() const {
return new ImageBlock(Vector2i(m_blockSize, m_blockSize), m_borderSize,
true, true, true, m_collectStatistics);
}
void prepare() {
m_scene = new Scene(static_cast(getResource("scene")));
/// Variance estimates are required when executing a T-test on the rendered data
m_collectStatistics = (m_scene->getTestType() == Scene::ETTest);
m_sampler = static_cast(getResource("sampler"));
m_camera = static_cast(getResource("camera"));
m_integrator = static_cast(getResource("integrator"));
m_scene->setCamera(m_camera);
m_scene->setSampler(m_sampler);
m_scene->setIntegrator(m_integrator);
m_integrator->wakeup(m_resources);
m_scene->wakeup(m_resources);
}
void process(const WorkUnit *workUnit, WorkResult *workResult,
const bool &stop) {
const RectangularWorkUnit *rect = static_cast(workUnit);
ImageBlock *block = static_cast(workResult);
#ifdef MTS_DEBUG_FP
enableFPExceptions();
#endif
block->setOffset(rect->getOffset());
block->setSize(rect->getSize());
m_hilbertCurve.initialize(rect->getSize());
m_integrator->renderBlock(m_scene, m_camera, m_sampler,
block, stop, &m_hilbertCurve.getPoints());
#ifdef MTS_DEBUG_FP
disableFPExceptions();
#endif
}
void serialize(Stream *stream, InstanceManager *manager) const {
stream->writeInt(m_blockSize);
stream->writeInt(m_borderSize);
stream->writeBool(m_collectStatistics);
}
ref clone() const {
return new BlockRenderer(m_blockSize, m_borderSize);
}
MTS_DECLARE_CLASS()
protected:
virtual ~BlockRenderer() { }
private:
ref m_scene;
ref m_camera;
ref m_sampler;
ref m_integrator;
int m_blockSize;
int m_borderSize;
int m_collectStatistics;
HilbertCurve2D m_hilbertCurve;
};
BlockedRenderProcess::BlockedRenderProcess(const RenderJob *parent, RenderQueue *queue,
int blockSize) : m_queue(queue), m_progress(NULL) {
m_blockSize = blockSize;
m_parent = parent;
m_resultCount = 0;
m_resultMutex = new Mutex();
}
BlockedRenderProcess::~BlockedRenderProcess() {
if (m_progress)
delete m_progress;
}
ref BlockedRenderProcess::createWorkProcessor() const {
return new BlockRenderer(m_blockSize, m_borderSize);
}
void BlockedRenderProcess::processResult(const WorkResult *result, bool cancelled) {
const ImageBlock *block = static_cast(result);
m_resultMutex->lock();
m_film->putImageBlock(block);
m_progress->update(++m_resultCount);
m_resultMutex->unlock();
m_queue->signalWorkEnd(m_parent, block);
}
ParallelProcess::EStatus BlockedRenderProcess::generateWork(WorkUnit *unit, int worker) {
EStatus status = BlockedImageProcess::generateWork(unit, worker);
if (status == ESuccess)
m_queue->signalWorkBegin(m_parent, static_cast(unit), worker);
return status;
}
void BlockedRenderProcess::bindResource(const std::string &name, int id) {
if (name == "camera") {
m_film = static_cast(Scheduler::getInstance()->getResource(id))->getFilm();
const TabulatedFilter *filter = m_film->getTabulatedFilter();
m_borderSize = (int) std::ceil(std::max(filter->getFilterSize().x,
filter->getFilterSize().y) - (Float) 0.5);
Point2i offset = m_film->getCropOffset();
Vector2i size = m_film->getCropSize();
if (m_film->hasHighQualityEdges()) {
offset.x -= m_borderSize;
offset.y -= m_borderSize;
size.x += 2 * m_borderSize;
size.y += 2 * m_borderSize;
}
BlockedImageProcess::init(offset, size, m_blockSize);
if (m_progress)
delete m_progress;
m_progress = new ProgressReporter("Rendering", m_numBlocksTotal, m_parent);
}
BlockedImageProcess::bindResource(name, id);
}
MTS_IMPLEMENT_CLASS(BlockedRenderProcess, false, BlockedImageProcess)
MTS_IMPLEMENT_CLASS_S(BlockRenderer, false, WorkProcessor)
MTS_NAMESPACE_END