void process(const WorkUnit *workUnit, WorkResult *workResult, const bool &stop) { const RectangularWorkUnit *rect = static_cast<const RectangularWorkUnit *>(workUnit); ImageBlock *block = static_cast<ImageBlock *>(workResult); #ifdef MTS_DEBUG_FP enableFPExceptions(); #endif block->setOffset(rect->getOffset()); block->setSize(rect->getSize()); m_hilbertCurve.initialize(TVector2<uint8_t>(rect->getSize())); m_integrator->renderBlock(m_scene, m_sensor, m_sampler, block, stop, m_hilbertCurve.getPoints()); #ifdef MTS_DEBUG_FP disableFPExceptions(); #endif }
void restoreFPExceptions(bool oldState) { bool currentState; #if defined(WIN32) uint32_t cw = _controlfp(0, 0); currentState = ~cw & (_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW); #elif defined(__OSX__) #if !defined(MTS_SSE) #warning SSE must be enabled to handle FP exceptions on OSX #else currentState = query_fpexcept_sse() != 0; #endif #else currentState = fegetexcept() & (FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW); #endif if (oldState != currentState) { if (oldState) enableFPExceptions(); else disableFPExceptions(); } }
bool render(Scene *scene, RenderQueue *queue, const RenderJob *job, int sceneResID, int cameraResID, int unused) { ref<Scheduler> sched = Scheduler::getInstance(); ref<Camera> camera = scene->getCamera(); ref<Film> film = camera->getFilm(); size_t nCores = sched->getCoreCount(); Log(EInfo, "Starting render job (%ix%i, " SIZE_T_FMT " %s, " SSE_STR ") ..", film->getCropSize().x, film->getCropSize().y, nCores, nCores == 1 ? "core" : "cores"); Vector2i cropSize = film->getCropSize(); Point2i cropOffset = film->getCropOffset(); m_gatherBlocks.clear(); m_running = true; m_totalEmitted = 0; ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()-> createObject(MTS_CLASS(Sampler), Properties("independent"))); /* Allocate memory */ m_bitmap = new Bitmap(film->getSize().x, film->getSize().y, 128); m_bitmap->clear(); for (int yofs=0; yofs<cropSize.y; yofs += m_blockSize) { for (int xofs=0; xofs<cropSize.x; xofs += m_blockSize) { m_gatherBlocks.push_back(std::vector<GatherPoint>()); m_offset.push_back(Point2i(cropOffset.x + xofs, cropOffset.y + yofs)); std::vector<GatherPoint> &gatherPoints = m_gatherBlocks[m_gatherBlocks.size()-1]; int nPixels = std::min(m_blockSize, cropSize.y-yofs) * std::min(m_blockSize, cropSize.x-xofs); gatherPoints.resize(nPixels); for (int i=0; i<nPixels; ++i) gatherPoints[i].radius = m_initialRadius; } } /* Create a sampler instance for every core */ std::vector<SerializableObject *> samplers(sched->getCoreCount()); for (size_t i=0; i<sched->getCoreCount(); ++i) { ref<Sampler> clonedSampler = sampler->clone(); clonedSampler->incRef(); samplers[i] = clonedSampler.get(); } int samplerResID = sched->registerManifoldResource( static_cast<std::vector<SerializableObject*> &>(samplers)); #ifdef MTS_DEBUG_FP enableFPExceptions(); #endif int it=0; while (m_running) { distributedRTPass(scene, samplers); photonMapPass(++it, queue, job, film, sceneResID, cameraResID, samplerResID); } #ifdef MTS_DEBUG_FP disableFPExceptions(); #endif for (size_t i=0; i<sched->getCoreCount(); ++i) samplers[i]->decRef(); sched->unregisterResource(samplerResID); return true; }
void process(const WorkUnit *workUnit, WorkResult *workResult, const bool &stop) { ImageBlock *result = static_cast<ImageBlock *>(workResult); const SeedWorkUnit *wu = static_cast<const SeedWorkUnit *>(workUnit); Path *current = new Path(), *proposed = new Path(); Spectrum relWeight(0.0f); result->clear(); /// Reconstruct the seed path m_pathSampler->reconstructPath(wu->getSeed(), m_config.importanceMap, *current); relWeight = current->getRelativeWeight(); BDAssert(!relWeight.isZero()); DiscreteDistribution suitabilities(m_mutators.size()); MutationRecord muRec, currentMuRec(Mutator::EMutationTypeCount,0,0,0,Spectrum(0.f)); ref<Timer> timer = new Timer(); size_t consecRejections = 0; Float accumulatedWeight = 0; #if defined(MTS_DEBUG_FP) enableFPExceptions(); #endif #if defined(MTS_BD_DEBUG_HEAVY) std::ostringstream oss; Path backup; #endif for (size_t mutationCtr=0; mutationCtr < m_config.nMutations && !stop; ++mutationCtr) { if (wu->getTimeout() > 0 && (mutationCtr % 8192) == 0 && (int) timer->getMilliseconds() > wu->getTimeout()) break; /* Query all mutators for their suitability */ suitabilities.clear(); for (size_t j=0; j<m_mutators.size(); ++j) suitabilities.append(m_mutators[j]->suitability(*current)); #if defined(MTS_BD_DEBUG_HEAVY) current->clone(backup, *m_pool); #endif size_t mutatorIdx = 0; bool success = false; Mutator *mutator = NULL; if (suitabilities.normalize() == 0) { /* No mutator can handle this path -- give up */ size_t skip = m_config.nMutations - mutationCtr; accumulatedWeight += skip; consecRejections += skip; break; } mutatorIdx = suitabilities.sample(m_sampler->next1D()); mutator = m_mutators[mutatorIdx].get(); /* Sample a mutated path */ success = mutator->sampleMutation(*current, *proposed, muRec, currentMuRec); #if defined(MTS_BD_DEBUG_HEAVY) if (backup != *current) Log(EError, "Detected an unexpected path modification after a " "mutation of type %s (k=%i)!", muRec.toString().c_str(), current->length()); if (success) { bool fail = false; for (int i=0; i<muRec.l; ++i) if (*backup.vertex(i) != *proposed->vertex(i)) fail = true; for (int i=1; i <= backup.length() - muRec.m; ++i) if (*backup.vertex(muRec.m+i) != *proposed->vertex(muRec.l+muRec.ka+i)) fail = true; if (fail) Log(EError, "Detected an unexpected path modification outside of the " "specified range after a mutation of type %s (k=%i)!", muRec.toString().c_str(), current->length()); } backup.release(*m_pool); #endif statsAccepted.incrementBase(1); if (success) { Float Qxy = mutator->Q(*current, *proposed, muRec) * suitabilities[mutatorIdx]; suitabilities.clear(); for (size_t j=0; j<m_mutators.size(); ++j) suitabilities.append(m_mutators[j]->suitability(*proposed)); suitabilities.normalize(); Float Qyx = mutator->Q(*proposed, *current, muRec.reverse()) * suitabilities[mutatorIdx]; Float a; if (!m_config.importanceMap) { if(Qxy > RCPOVERFLOW) a = std::min((Float) 1, Qyx / Qxy); else a = 0.f; } else { const Float *luminanceValues = m_config.importanceMap->getFloatData(); const Point2 &curPos = current->getSamplePosition(); const Point2 &propPos = proposed->getSamplePosition(); Vector2i size = m_config.importanceMap->getSize(); Point2i curPosI( std::min(std::max(0, (int) curPos.x), size.x-1), std::min(std::max(0, (int) curPos.y), size.y-1)); Point2i propPosI( std::min(std::max(0, (int) propPos.x), size.x-1), std::min(std::max(0, (int) propPos.y), size.y-1)); Float curValue = luminanceValues[curPosI.x + curPosI.y * size.x]; Float propValue = luminanceValues[propPosI.x + propPosI.y * size.x]; a = std::min((Float) 1, (Qyx * curValue) / (Qxy * propValue)); } #if defined(MTS_BD_DEBUG_HEAVY) if (!proposed->verify(m_scene, EImportance, oss)) { Log(EWarn, "%s proposed as %s, Qxy=%f, Qyx=%f", oss.str().c_str(), muRec.toString().c_str(), Qxy, Qyx); proposed->release(muRec.l, muRec.l + muRec.ka + 1, *m_pool); oss.str(""); continue; } #endif if (Qxy == 0) { // be tolerant of this (can occasionally happen due to floating point inaccuracies) a = 0; } else if (Qxy < 0 || Qyx < 0 || std::isnan(Qxy) || std::isnan(Qyx)) { #if defined(MTS_BD_DEBUG) Log(EDebug, "Source path: %s", current->toString().c_str()); Log(EDebug, "Proposal path: %s", proposed->toString().c_str()); Log(EWarn, "Internal error while computing acceptance probabilities: " "Qxy=%f, Qyx=%f, muRec=%s", Qxy, Qyx, muRec.toString().c_str()); #endif a = 0; } accumulatedWeight += 1-a; /* Accept with probability 'a' */ if (a == 1 || m_sampler->next1D() < a) { current->release(muRec.l, muRec.m+1, *m_pool); Spectrum value = relWeight * accumulatedWeight; if (!value.isZero()) result->put(current->getSamplePosition(), &value[0]); /* The mutation was accepted */ std::swap(current, proposed); relWeight = current->getRelativeWeight(); mutator->accept(muRec); currentMuRec = muRec; accumulatedWeight = a; consecRejections = 0; ++statsAccepted; } else { /* The mutation was rejected */ proposed->release(muRec.l, muRec.l + muRec.ka + 1, *m_pool); consecRejections++; if (a > 0) { Spectrum value = proposed->getRelativeWeight() * a; result->put(proposed->getSamplePosition(), &value[0]); } } } else { accumulatedWeight += 1; consecRejections++; } } #if defined(MTS_BD_DEBUG) if (consecRejections == m_config.nMutations) Log(EWarn, "Encountered a path that could *never* be mutated!: %s", current->toString().c_str()); #endif if (accumulatedWeight > 0) { Spectrum value = relWeight * accumulatedWeight; result->put(current->getSamplePosition(), &value[0]); } #if defined(MTS_DEBUG_FP) disableFPExceptions(); #endif current->release(*m_pool); delete current; delete proposed; if (!m_pool->unused()) Log(EError, "Internal error: detected a memory pool leak!"); }
bool render(Scene *scene, RenderQueue *queue, const RenderJob *job, int sceneResID, int cameraResID, int samplerResID) { ref<Scheduler> sched = Scheduler::getInstance(); ref<Camera> camera = scene->getCamera(); ref<Film> film = camera->getFilm(); size_t nCores = sched->getCoreCount(); Sampler *cameraSampler = (Sampler *) sched->getResource(samplerResID, 0); size_t sampleCount = cameraSampler->getSampleCount(); Log(EInfo, "Starting render job (%ix%i, " SIZE_T_FMT " %s, " SIZE_T_FMT " %s, " SSE_STR ") ..", film->getCropSize().x, film->getCropSize().y, sampleCount, sampleCount == 1 ? "sample" : "samples", nCores, nCores == 1 ? "core" : "cores"); Vector2i cropSize = film->getCropSize(); Point2i cropOffset = film->getCropOffset(); m_gatherPoints.clear(); m_running = true; for (size_t i=0; i<m_blocks.size(); ++i) m_blocks[i]->decRef(); m_blocks.clear(); m_totalEmitted = 0; bool needsLensSample = camera->needsLensSample(); bool needsTimeSample = camera->needsTimeSample(); Log(EInfo, "Creating approximately %i gather points", cropSize.x*cropSize.y*sampleCount); Point2 lensSample, sample; RayDifferential eyeRay; Float timeSample = 0; m_filter = camera->getFilm()->getTabulatedFilter(); Vector2 filterSize = m_filter->getFilterSize(); int borderSize = (int) std::ceil(std::max(filterSize.x, filterSize.y)); ref<Sampler> independentSampler = static_cast<Sampler *> (PluginManager::getInstance()-> createObject(MTS_CLASS(Sampler), Properties("independent"))); /* Create a sampler instance for every core */ std::vector<SerializableObject *> samplers(sched->getCoreCount()); for (size_t i=0; i<sched->getCoreCount(); ++i) { ref<Sampler> clonedSampler = independentSampler->clone(); clonedSampler->incRef(); samplers[i] = clonedSampler.get(); } int independentSamplerResID = sched->registerManifoldResource(samplers); for (size_t i=0; i<sched->getCoreCount(); ++i) samplers[i]->decRef(); #ifdef MTS_DEBUG_FP enableFPExceptions(); #endif /* Create gather points in blocks so that gathering can be parallelized later on */ for (int yofs=0; yofs<cropSize.y; yofs += m_blockSize) { for (int xofs=0; xofs<cropSize.x; xofs += m_blockSize) { ImageBlock *block = new ImageBlock(Vector2i(m_blockSize, m_blockSize), borderSize, true, true, false, false); block->setSize(Vector2i(m_blockSize, m_blockSize)); block->setOffset(Point2i(cropOffset.x + xofs, cropOffset.y + yofs)); block->incRef(); std::vector<GatherPoint> gatherPoints; gatherPoints.reserve(m_blockSize*m_blockSize*sampleCount); for (int yofsInt = 0; yofsInt < m_blockSize; ++yofsInt) { if (yofsInt + yofs >= cropSize.y) continue; for (int xofsInt = 0; xofsInt < m_blockSize; ++xofsInt) { if (xofsInt + xofs >= cropSize.x) continue; int y = cropOffset.y + yofs + yofsInt; int x = cropOffset.x + xofs + xofsInt; cameraSampler->generate(); for (size_t j = 0; j<sampleCount; j++) { if (needsLensSample) lensSample = cameraSampler->next2D(); if (needsTimeSample) timeSample = cameraSampler->next1D(); sample = cameraSampler->next2D(); sample.x += x; sample.y += y; camera->generateRayDifferential(sample, lensSample, timeSample, eyeRay); size_t offset = gatherPoints.size(); Float count = (Float) createGatherPoints(scene, eyeRay, sample, cameraSampler, Spectrum(1.0f), gatherPoints, 1); if (count > 1) { // necessary because of filter weight computation for (int i = 0; i<count; ++i) gatherPoints[offset+i].weight *= count; } cameraSampler->advance(); } } } m_blocks.push_back(block); m_gatherPoints.push_back(gatherPoints); } } int it=0; while (m_running) photonMapPass(++it, queue, job, film, sceneResID, cameraResID, independentSamplerResID); #ifdef MTS_DEBUG_FP disableFPExceptions(); #endif sched->unregisterResource(independentSamplerResID); return true; }