Patch by Tom Kazimiers: automatically cancel photon gathering if few or no photons are being generated

metadata
Wenzel Jakob 2011-07-15 10:15:57 +02:00
parent 5a714c3bc6
commit 5f27a96432
5 changed files with 51 additions and 9 deletions

View File

@ -53,12 +53,15 @@ public:
* \param isLocal * \param isLocal
* Should the parallel process only be executed locally? (sending * Should the parallel process only be executed locally? (sending
* photons over the network may be unnecessary and wasteful) * photons over the network may be unnecessary and wasteful)
* \param autoCancel
* Indicates if the gathering process should be canceled if there
* are not enough photons generated
* \param progressReporterPayload * \param progressReporterPayload
* Custom pointer payload to be delivered with progress messages * Custom pointer payload to be delivered with progress messages
*/ */
GatherPhotonProcess(EGatherType type, size_t photonCount, GatherPhotonProcess(EGatherType type, size_t photonCount,
size_t granularity, int maxDepth, int rrDepth, bool isLocal, size_t granularity, int maxDepth, int rrDepth, bool isLocal,
const void *progressReporterPayload); bool autoCancel, const void *progressReporterPayload);
/** /**
* Once the process has finished, this returns a reference * Once the process has finished, this returns a reference
@ -89,6 +92,7 @@ public:
bool isLocal() const; bool isLocal() const;
ref<WorkProcessor> createWorkProcessor() const; ref<WorkProcessor> createWorkProcessor() const;
void processResult(const WorkResult *wr, bool cancelled); void processResult(const WorkResult *wr, bool cancelled);
EStatus generateWork(WorkUnit *unit, int worker);
/// @} /// @}
// ====================================================================== // ======================================================================
@ -97,12 +101,23 @@ public:
protected: protected:
/// Virtual destructor /// Virtual destructor
virtual ~GatherPhotonProcess() { } virtual ~GatherPhotonProcess() { }
/**
* \brief Checks if the configuration of needed, generated and shot
* photons indicates an unsuccessful progress of the gathering. This
* check is taken from PBRT.
*/
inline bool unsuccessful(size_t needed, size_t gen, size_t shot) {
return (gen < needed && (gen == 0 || gen < shot/1024));
}
protected: protected:
EGatherType m_type; EGatherType m_type;
ref<PhotonMap> m_photonMap; ref<PhotonMap> m_photonMap;
size_t m_photonCount;
int m_maxDepth; int m_maxDepth;
int m_rrDepth; int m_rrDepth;
bool m_isLocal; bool m_isLocal;
bool m_autoCancel;
size_t m_excess, m_numShot; size_t m_excess, m_numShot;
}; };

View File

@ -60,6 +60,8 @@ public:
m_volumeLookupSize = props.getInteger("volumeLookupSize", 120); m_volumeLookupSize = props.getInteger("volumeLookupSize", 120);
/* Should photon gathering steps exclusively run on the local machine? */ /* Should photon gathering steps exclusively run on the local machine? */
m_gatherLocally = props.getBoolean("gatherLocally", true); m_gatherLocally = props.getBoolean("gatherLocally", true);
/* Indicates if the gathering steps should be canceled if not enough photons are generated. */
m_autoCancelGathering = props.getBoolean("autoCancelGathering", true);
} }
/// Unserialize from a binary data stream /// Unserialize from a binary data stream
@ -77,6 +79,7 @@ public:
m_causticLookupSize = stream->readInt(); m_causticLookupSize = stream->readInt();
m_volumeLookupSize = stream->readInt(); m_volumeLookupSize = stream->readInt();
m_gatherLocally = stream->readBool(); m_gatherLocally = stream->readBool();
m_autoCancelGathering = stream->readBool();
} }
void serialize(Stream *stream, InstanceManager *manager) const { void serialize(Stream *stream, InstanceManager *manager) const {
@ -93,6 +96,7 @@ public:
stream->writeInt(m_causticLookupSize); stream->writeInt(m_causticLookupSize);
stream->writeInt(m_volumeLookupSize); stream->writeInt(m_volumeLookupSize);
stream->writeBool(m_gatherLocally); stream->writeBool(m_gatherLocally);
stream->writeBool(m_autoCancelGathering);
} }
/// Configure the sampler for a specified amount of direct illumination samples /// Configure the sampler for a specified amount of direct illumination samples
@ -142,7 +146,8 @@ public:
/* Generate the global photon map */ /* Generate the global photon map */
ref<GatherPhotonProcess> proc = new GatherPhotonProcess( ref<GatherPhotonProcess> proc = new GatherPhotonProcess(
GatherPhotonProcess::ESurfacePhotons, m_globalPhotons, GatherPhotonProcess::ESurfacePhotons, m_globalPhotons,
m_granularity, m_maxDepth, m_rrDepth, m_gatherLocally, job); m_granularity, m_maxDepth, m_rrDepth, m_gatherLocally,
m_autoCancelGathering, job);
proc->bindResource("scene", sceneResID); proc->bindResource("scene", sceneResID);
proc->bindResource("camera", cameraResID); proc->bindResource("camera", cameraResID);
@ -172,7 +177,8 @@ public:
/* Generate the caustic photon map */ /* Generate the caustic photon map */
ref<GatherPhotonProcess> proc = new GatherPhotonProcess( ref<GatherPhotonProcess> proc = new GatherPhotonProcess(
GatherPhotonProcess::ECausticPhotons, m_causticPhotons, GatherPhotonProcess::ECausticPhotons, m_causticPhotons,
m_granularity, 2, m_rrDepth, m_gatherLocally, job); m_granularity, 2, m_rrDepth, m_gatherLocally,
m_autoCancelGathering, job);
proc->bindResource("scene", sceneResID); proc->bindResource("scene", sceneResID);
proc->bindResource("camera", cameraResID); proc->bindResource("camera", cameraResID);
@ -199,7 +205,8 @@ public:
/* Generate the volume photon map */ /* Generate the volume photon map */
ref<GatherPhotonProcess> proc = new GatherPhotonProcess( ref<GatherPhotonProcess> proc = new GatherPhotonProcess(
GatherPhotonProcess::EVolumePhotons, m_volumePhotons, GatherPhotonProcess::EVolumePhotons, m_volumePhotons,
m_granularity, m_maxDepth, m_rrDepth, m_gatherLocally, job); m_granularity, m_maxDepth, m_rrDepth, m_gatherLocally,
m_autoCancelGathering, job);
proc->bindResource("scene", sceneResID); proc->bindResource("scene", sceneResID);
proc->bindResource("camera", cameraResID); proc->bindResource("camera", cameraResID);
@ -426,6 +433,7 @@ private:
int m_rrDepth; int m_rrDepth;
int m_maxDepth, m_maxSpecularDepth; int m_maxDepth, m_maxSpecularDepth;
bool m_gatherLocally; bool m_gatherLocally;
bool m_autoCancelGathering;
}; };
MTS_IMPLEMENT_CLASS_S(PhotonMapIntegrator, false, SampleIntegrator) MTS_IMPLEMENT_CLASS_S(PhotonMapIntegrator, false, SampleIntegrator)

View File

@ -63,6 +63,8 @@ public:
m_rrDepth = props.getInteger("rrDepth", 3); m_rrDepth = props.getInteger("rrDepth", 3);
/* Block size used to parallelize the photon query passes (default: 32x32 pixels). */ /* Block size used to parallelize the photon query passes (default: 32x32 pixels). */
m_blockSize = props.getInteger("blockSize", 32); m_blockSize = props.getInteger("blockSize", 32);
/* Indicates if the gathering steps should be canceled if not enough photons are generated. */
m_autoCancelGathering = props.getBoolean("autoCancelGathering", true);
m_mutex = new Mutex(); m_mutex = new Mutex();
#if defined(__OSX__) #if defined(__OSX__)
Log(EError, "Progressive photon mapping currently doesn't work " Log(EError, "Progressive photon mapping currently doesn't work "
@ -277,7 +279,8 @@ public:
/* Generate the global photon map */ /* Generate the global photon map */
ref<GatherPhotonProcess> proc = new GatherPhotonProcess( ref<GatherPhotonProcess> proc = new GatherPhotonProcess(
GatherPhotonProcess::EAllSurfacePhotons, m_photonCount, GatherPhotonProcess::EAllSurfacePhotons, m_photonCount,
m_granularity, m_maxDepth == -1 ? -1 : (m_maxDepth-1), m_rrDepth, true, job); m_granularity, m_maxDepth == -1 ? -1 : (m_maxDepth-1), m_rrDepth, true,
m_autoCancelGathering, job);
proc->bindResource("scene", sceneResID); proc->bindResource("scene", sceneResID);
proc->bindResource("camera", cameraResID); proc->bindResource("camera", cameraResID);
@ -351,6 +354,7 @@ private:
size_t m_totalEmitted; size_t m_totalEmitted;
int m_blockSize; int m_blockSize;
bool m_running; bool m_running;
bool m_autoCancelGathering;
}; };
MTS_IMPLEMENT_CLASS_S(ProgressivePhotonMapIntegrator, false, Integrator) MTS_IMPLEMENT_CLASS_S(ProgressivePhotonMapIntegrator, false, Integrator)

View File

@ -64,6 +64,8 @@ public:
m_rrDepth = props.getInteger("rrDepth", 3); m_rrDepth = props.getInteger("rrDepth", 3);
/* Block size used to parallelize the photon query passes (default: 32x32 pixels). */ /* Block size used to parallelize the photon query passes (default: 32x32 pixels). */
m_blockSize = props.getInteger("blockSize", 32); m_blockSize = props.getInteger("blockSize", 32);
/* Indicates if the gathering steps should be canceled if not enough photons are generated. */
m_autoCancelGathering = props.getBoolean("autoCancelGathering", true);
m_mutex = new Mutex(); m_mutex = new Mutex();
#if defined(__OSX__) #if defined(__OSX__)
Log(EError, "Stochastic progressive photon mapping currently doesn't work " Log(EError, "Stochastic progressive photon mapping currently doesn't work "
@ -265,7 +267,8 @@ public:
/* Generate the global photon map */ /* Generate the global photon map */
ref<GatherPhotonProcess> proc = new GatherPhotonProcess( ref<GatherPhotonProcess> proc = new GatherPhotonProcess(
GatherPhotonProcess::EAllSurfacePhotons, m_photonCount, GatherPhotonProcess::EAllSurfacePhotons, m_photonCount,
m_granularity, m_maxDepth-1, m_rrDepth, true, job); m_granularity, m_maxDepth-1, m_rrDepth, true,
m_autoCancelGathering, job);
proc->bindResource("scene", sceneResID); proc->bindResource("scene", sceneResID);
proc->bindResource("camera", cameraResID); proc->bindResource("camera", cameraResID);
@ -339,6 +342,7 @@ private:
size_t m_totalEmitted; size_t m_totalEmitted;
int m_blockSize; int m_blockSize;
bool m_running; bool m_running;
bool m_autoCancelGathering;
}; };
MTS_IMPLEMENT_CLASS_S(StochasticProgressivePhotonMapIntegrator, false, Integrator) MTS_IMPLEMENT_CLASS_S(StochasticProgressivePhotonMapIntegrator, false, Integrator)

View File

@ -169,10 +169,11 @@ protected:
}; };
GatherPhotonProcess::GatherPhotonProcess(EGatherType type, size_t photonCount, GatherPhotonProcess::GatherPhotonProcess(EGatherType type, size_t photonCount,
size_t granularity, int maxDepth, int rrDepth, bool isLocal, const void *progressReporterPayload) size_t granularity, int maxDepth, int rrDepth, bool isLocal, bool autoCancel,
const void *progressReporterPayload)
: ParticleProcess(ParticleProcess::EGather, photonCount, granularity, "Gathering photons", : ParticleProcess(ParticleProcess::EGather, photonCount, granularity, "Gathering photons",
progressReporterPayload), m_type(type), m_maxDepth(maxDepth), m_rrDepth(rrDepth), progressReporterPayload), m_type(type), m_photonCount(photonCount), m_maxDepth(maxDepth),
m_isLocal(isLocal), m_excess(0), m_numShot(0) { m_rrDepth(rrDepth), m_isLocal(isLocal), m_autoCancel(autoCancel), m_excess(0), m_numShot(0) {
m_photonMap = new PhotonMap(photonCount); m_photonMap = new PhotonMap(photonCount);
} }
@ -211,6 +212,16 @@ void GatherPhotonProcess::processResult(const WorkResult *wr, bool cancelled) {
m_resultMutex->unlock(); m_resultMutex->unlock();
} }
ParallelProcess::EStatus GatherPhotonProcess::generateWork(WorkUnit *unit, int worker) {
/* Use the same approach as PBRT for auto canceling */
if (m_autoCancel && m_numShot > 500000
&& unsuccessful(m_photonCount, m_photonMap->getPhotonCount(), m_numShot)) {
Log(EInfo, "Not enough photons could be collected, giving up");
return EFailure;
}
return ParticleProcess::generateWork(unit, worker);
}
MTS_IMPLEMENT_CLASS(GatherPhotonProcess, false, ParticleProcess) MTS_IMPLEMENT_CLASS(GatherPhotonProcess, false, ParticleProcess)
MTS_IMPLEMENT_CLASS_S(GatherPhotonWorker, false, ParticleTracer) MTS_IMPLEMENT_CLASS_S(GatherPhotonWorker, false, ParticleTracer)