HybridRenderEngine::HybridRenderEngine(RenderConfig *rcfg, Film *flm, boost::mutex *flmMutex) : OCLRenderEngine(rcfg, flm, flmMutex, false) { //-------------------------------------------------------------------------- // Create the intersection devices and render threads //-------------------------------------------------------------------------- if (selectedDeviceDescs.empty()) { SLG_LOG("No OpenCL device found, falling back to CPU rendering"); selectedDeviceDescs = ctx->GetAvailableDeviceDescriptions(); DeviceDescription::Filter(DEVICE_TYPE_NATIVE_THREAD, selectedDeviceDescs); if (selectedDeviceDescs.empty()) throw runtime_error("No native CPU device found"); } const size_t renderThreadCount = boost::thread::hardware_concurrency(); if (selectedDeviceDescs.size() == 1) { // Only one intersection device, use a M2O device intersectionDevices = ctx->AddVirtualM2OIntersectionDevices(renderThreadCount, selectedDeviceDescs); } else { // Multiple intersection devices, use a M2M device intersectionDevices = ctx->AddVirtualM2MIntersectionDevices(renderThreadCount, selectedDeviceDescs); } devices = ctx->GetIntersectionDevices(); // Set the LuxRays DataSet ctx->SetDataSet(renderConfig->scene->dataSet); SLG_LOG("Starting "<< renderThreadCount << " BiDir hybrid render threads"); renderThreads.resize(renderThreadCount, NULL); }
void SLGTerminate(void) { SLG_LOG("========================================================="); SLG_LOG("Unhandled exception"); void *array[32]; size_t size = backtrace(array, 32); char **strings = backtrace_symbols(array, size); SLG_LOG("Obtained " << size << " stack frames."); for (size_t i = 0; i < size; i++) SLG_LOG(" " << Demangle(strings[i])); free(strings); }
CPURenderEngine::CPURenderEngine(RenderConfig *cfg, Film *flm, boost::mutex *flmMutex) : RenderEngine(cfg, flm, flmMutex) { const size_t renderThreadCount = cfg->cfg.GetInt("native.threads.count", boost::thread::hardware_concurrency()); //-------------------------------------------------------------------------- // Allocate devices //-------------------------------------------------------------------------- vector<DeviceDescription *> devDescs = ctx->GetAvailableDeviceDescriptions(); DeviceDescription::Filter(DEVICE_TYPE_NATIVE_THREAD, devDescs); selectedDeviceDescs.resize(renderThreadCount, NULL); for (size_t i = 0; i < selectedDeviceDescs.size(); ++i) selectedDeviceDescs[i] = devDescs[i % devDescs.size()]; intersectionDevices = ctx->AddIntersectionDevices(selectedDeviceDescs); for (size_t i = 0; i < intersectionDevices.size(); ++i) { // Disable the support for hybrid rendering in order to not waste resource intersectionDevices[i]->SetDataParallelSupport(false); } // Set the LuxRays SataSet ctx->SetDataSet(renderConfig->scene->dataSet); //-------------------------------------------------------------------------- // Setup render threads array //-------------------------------------------------------------------------- SLG_LOG("Configuring "<< renderThreadCount << " CPU render threads"); renderThreads.resize(renderThreadCount, NULL); }
RenderEngine *RenderEngine::AllocRenderEngine(const RenderEngineType engineType, RenderConfig *renderConfig, Film *film, boost::mutex *filmMutex) { switch (engineType) { case LIGHTCPU: return new LightCPURenderEngine(renderConfig, film, filmMutex); case PATHOCL: #ifndef LUXRAYS_DISABLE_OPENCL return new PathOCLRenderEngine(renderConfig, film, filmMutex); #else SLG_LOG("OpenCL unavailable, falling back to CPU rendering"); #endif case PATHCPU: return new PathCPURenderEngine(renderConfig, film, filmMutex); case BIDIRCPU: return new BiDirCPURenderEngine(renderConfig, film, filmMutex); case BIDIRHYBRID: return new BiDirHybridRenderEngine(renderConfig, film, filmMutex); case CBIDIRHYBRID: return new CBiDirHybridRenderEngine(renderConfig, film, filmMutex); case BIDIRVMCPU: return new BiDirVMCPURenderEngine(renderConfig, film, filmMutex); case FILESAVER: return new FileSaverRenderEngine(renderConfig, film, filmMutex); default: throw runtime_error("Unknown render engine type: " + boost::lexical_cast<std::string>(engineType)); } }
void PathOCLRenderThread::AllocOCLBufferRO(cl::Buffer **buff, void *src, const size_t size, const string &desc) { const OpenCLDeviceDescription *deviceDesc = intersectionDevice->GetDeviceDesc(); if (*buff) { // Check the size of the already allocated buffer if (size == (*buff)->getInfo<CL_MEM_SIZE>()) { // I can reuse the buffer; just update the content //SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] " << desc << " buffer updated for size: " << (size / 1024) << "Kbytes"); cl::CommandQueue &oclQueue = intersectionDevice->GetOpenCLQueue(); oclQueue.enqueueWriteBuffer(**buff, CL_FALSE, 0, size, src); return; } else { // Free the buffer deviceDesc->FreeMemory((*buff)->getInfo<CL_MEM_SIZE>()); delete *buff; } } cl::Context &oclContext = intersectionDevice->GetOpenCLContext(); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] " << desc << " buffer size: " << (size / 1024) << "Kbytes"); *buff = new cl::Buffer(oclContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, size, src); deviceDesc->AllocMemory((*buff)->getInfo<CL_MEM_SIZE>()); }
void RenderSession::EndEdit() { assert (started); assert (editMode); if (editActions.Size() > 0) film->Reset(); SLG_LOG("[RenderSession] Edit actions: " << editActions); renderEngine->EndEdit(editActions); editMode = false; }
void PathOCLRenderThread::AllocOCLBufferRW(cl::Buffer **buff, const size_t size, const string &desc) { const OpenCLDeviceDescription *deviceDesc = intersectionDevice->GetDeviceDesc(); if (*buff) { // Check the size of the already allocated buffer if (size == (*buff)->getInfo<CL_MEM_SIZE>()) { // I can reuse the buffer //SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] " << desc << " buffer reused for size: " << (size / 1024) << "Kbytes"); return; } else { // Free the buffer deviceDesc->FreeMemory((*buff)->getInfo<CL_MEM_SIZE>()); delete *buff; } } cl::Context &oclContext = intersectionDevice->GetOpenCLContext(); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] " << desc << " buffer size: " << (size / 1024) << "Kbytes"); *buff = new cl::Buffer(oclContext, CL_MEM_READ_WRITE, size); deviceDesc->AllocMemory((*buff)->getInfo<CL_MEM_SIZE>()); }
void HybridRenderThread::RenderFunc() { //SLG_LOG("[HybridRenderThread::" << threadIndex << "] Rendering thread started"); boost::this_thread::disable_interruption di; Film *film = threadFilm; const u_int filmWidth = film->GetWidth(); const u_int filmHeight = film->GetHeight(); pixelCount = filmWidth * filmHeight; RandomGenerator *rndGen = new RandomGenerator(threadIndex + renderEngine->seedBase); const u_int incrementStep = 4096; vector<HybridRenderState *> states(incrementStep); try { // Initialize the first states for (u_int i = 0; i < states.size(); ++i) states[i] = AllocRenderState(rndGen); u_int generateIndex = 0; u_int collectIndex = 0; while (!boost::this_thread::interruption_requested()) { // Generate new rays up to the point to have 3 pending buffers while (pendingRayBuffers < 3) { states[generateIndex]->GenerateRays(this); generateIndex = (generateIndex + 1) % states.size(); if (generateIndex == collectIndex) { //SLG_LOG("[HybridRenderThread::" << threadIndex << "] Increasing states size by " << incrementStep); //SLG_LOG("[HybridRenderThread::" << threadIndex << "] State size: " << states.size()); // Insert a set of new states and continue states.insert(states.begin() + generateIndex, incrementStep, NULL); for (u_int i = generateIndex; i < generateIndex + incrementStep; ++i) states[i] = AllocRenderState(rndGen); collectIndex += incrementStep; } } //SLG_LOG("[HybridRenderThread::" << threadIndex << "] State size: " << states.size()); //SLG_LOG("[HybridRenderThread::" << threadIndex << "] generateIndex: " << generateIndex); //SLG_LOG("[HybridRenderThread::" << threadIndex << "] collectIndex: " << collectIndex); //SLG_LOG("[HybridRenderThread::" << threadIndex << "] pendingRayBuffers: " << pendingRayBuffers); // Collect rays up to the point to have only 1 pending buffer while (pendingRayBuffers > 1) { samplesCount += states[collectIndex]->CollectResults(this); const u_int newCollectIndex = (collectIndex + 1) % states.size(); // A safety-check, it should never happen if (newCollectIndex == generateIndex) break; collectIndex = newCollectIndex; } } //SLG_LOG("[HybridRenderThread::" << threadIndex << "] Rendering thread halted"); } catch (boost::thread_interrupted) { SLG_LOG("[HybridRenderThread::" << threadIndex << "] Rendering thread halted"); } #ifndef LUXRAYS_DISABLE_OPENCL catch (cl::Error err) { SLG_LOG("[HybridRenderThread::" << threadIndex << "] Rendering thread ERROR: " << err.what() << "(" << luxrays::utils::oclErrorString(err.err()) << ")"); } #endif // Clean current ray buffers if (currentRayBufferToSend) { currentRayBufferToSend->Reset(); freeRayBuffers.push_back(currentRayBufferToSend); currentRayBufferToSend = NULL; } if (currentReiceivedRayBuffer) { currentReiceivedRayBuffer->Reset(); freeRayBuffers.push_back(currentReiceivedRayBuffer); currentReiceivedRayBuffer = NULL; } // Free all states for (u_int i = 0; i < states.size(); ++i) delete states[i]; delete rndGen; // Remove all pending ray buffers while (pendingRayBuffers > 0) { RayBuffer *rayBuffer = device->PopRayBuffer(); --(pendingRayBuffers); rayBuffer->Reset(); freeRayBuffers.push_back(rayBuffer); } }
int main(int argc, char *argv[]) { #if defined(__GNUC__) && !defined(__CYGWIN__) set_terminate(SLGTerminate); #endif // This is required to run AMD GPU profiler //XInitThreads(); luxrays::sdl::LuxRaysSDLDebugHandler = SDLDebugHandler; try { // Initialize FreeImage Library FreeImage_Initialise(TRUE); FreeImage_SetOutputMessage(FreeImageErrorHandler); bool batchMode = false; bool telnetServerEnabled = false; Properties cmdLineProp; string configFileName; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { // I should check for out of range array index... if (argv[i][1] == 'h') { SLG_LOG("Usage: " << argv[0] << " [options] [configuration file]" << endl << " -o [configuration file]" << endl << " -f [scene file]" << endl << " -w [window width]" << endl << " -e [window height]" << endl << " -t [halt time in secs]" << endl << " -T <enable the telnet server>" << endl << " -D [property name] [property value]" << endl << " -d [current directory path]" << endl << " -m Makes the mouse operations work in \"grab mode\"" << endl << " -h <display this help and exit>"); exit(EXIT_SUCCESS); } else if (argv[i][1] == 'o') { if (configFileName.compare("") != 0) throw runtime_error("Used multiple configuration files"); configFileName = string(argv[++i]); } else if (argv[i][1] == 'e') cmdLineProp.SetString("image.height", argv[++i]); else if (argv[i][1] == 'w') cmdLineProp.SetString("image.width", argv[++i]); else if (argv[i][1] == 'f') cmdLineProp.SetString("scene.file", argv[++i]); else if (argv[i][1] == 't') cmdLineProp.SetString("batch.halttime", argv[++i]); else if (argv[i][1] == 'T') telnetServerEnabled = true; else if (argv[i][1] == 'm') mouseGrabMode = true; else if (argv[i][1] == 'D') { cmdLineProp.SetString(argv[i + 1], argv[i + 2]); i += 2; } else if (argv[i][1] == 'd') boost::filesystem::current_path(boost::filesystem::path(argv[++i])); else { SLG_LOG("Invalid option: " << argv[i]); exit(EXIT_FAILURE); } } else { string s = argv[i]; if ((s.length() >= 4) && (s.substr(s.length() - 4) == ".cfg")) { if (configFileName.compare("") != 0) throw runtime_error("Used multiple configuration files"); configFileName = s; } else throw runtime_error("Unknown file extension: " + s); } } if (configFileName.compare("") == 0) configFileName = "scenes/luxball/luxball.cfg"; RenderConfig *config = new RenderConfig(&configFileName, &cmdLineProp); const unsigned int halttime = config->cfg.GetInt("batch.halttime", 0); const unsigned int haltspp = config->cfg.GetInt("batch.haltspp", 0); const float haltthreshold = config->cfg.GetFloat("batch.haltthreshold", -1.f); if ((halttime > 0) || (haltspp > 0) || (haltthreshold >= 0.f)) batchMode = true; else batchMode = false; if (batchMode) { session = new RenderSession(config); // Check if I have to do tile rendering if (config->cfg.IsDefined("batch.tile")) return BatchTileMode(haltspp, haltthreshold); else return BatchSimpleMode(halttime, haltspp, haltthreshold); } else { // It is important to initialize OpenGL before OpenCL // (for OpenGL/OpenCL inter-operability) u_int width, height; config->GetScreenSize(&width, &height); InitGlut(argc, argv, width, height); session = new RenderSession(config); // Start the rendering session->Start(); if (telnetServerEnabled) { TelnetServer telnetServer(18081, session); RunGlut(); } else RunGlut(); } #if !defined(LUXRAYS_DISABLE_OPENCL) } catch (cl::Error err) { SLG_LOG("OpenCL ERROR: " << err.what() << "(" << luxrays::utils::oclErrorString(err.err()) << ")"); return EXIT_FAILURE; #endif } catch (runtime_error err) { SLG_LOG("RUNTIME ERROR: " << err.what()); return EXIT_FAILURE; } catch (exception err) { SLG_LOG("ERROR: " << err.what()); return EXIT_FAILURE; } return EXIT_SUCCESS; }
static int BatchSimpleMode(const double haltTime, const unsigned int haltSpp, const float haltThreshold) { RenderConfig *config = session->renderConfig; RenderEngine *engine = session->renderEngine; // Force the film update at 2.5secs (mostly used by PathOCL) config->SetScreenRefreshInterval(2500); // Start the rendering session->Start(); // Nothing to do if it is the FileSaverRenderEngine if (!dynamic_cast<FileSaverRenderEngine *>(engine)) { const double startTime = WallClockTime(); double lastFilmUpdate = WallClockTime(); char buf[512]; for (;;) { boost::this_thread::sleep(boost::posix_time::millisec(1000)); // Check if periodic save is enabled if (session->NeedPeriodicSave()) { // Time to save the image and film session->SaveFilmImage(); lastFilmUpdate = WallClockTime(); } else { // Film update may be required by some render engine to // update statistics, convergence test and more if (WallClockTime() - lastFilmUpdate > 5.0) { session->renderEngine->UpdateFilm(); lastFilmUpdate = WallClockTime(); } } const double now = WallClockTime(); const double elapsedTime = now - startTime; if ((haltTime > 0) && (elapsedTime >= haltTime)) break; const unsigned int pass = engine->GetPass(); if ((haltSpp > 0) && (pass >= haltSpp)) break; // Convergence test is update inside UpdateFilm() const float convergence = engine->GetConvergence(); if ((haltThreshold >= 0.f) && (1.f - convergence <= haltThreshold)) break; // Print some information about the rendering progress sprintf(buf, "[Elapsed time: %3d/%dsec][Samples %4d/%d][Convergence %f%%][Avg. samples/sec % 3.2fM on %.1fK tris]", int(elapsedTime), int(haltTime), pass, haltSpp, 100.f * convergence, engine->GetTotalSamplesSec() / 1000000.0, config->scene->dataSet->GetTotalTriangleCount() / 1000.0); SLG_LOG(buf); } } // Stop the rendering session->Stop(); // Save the rendered image session->SaveFilmImage(); delete session; SLG_LOG("Done."); return EXIT_SUCCESS; }
static int BatchTileMode(const unsigned int haltSpp, const float haltThreshold) { RenderConfig *config = session->renderConfig; RenderEngine *engine = session->renderEngine; // batch.halttime condition doesn't make sense in the context // of tile rendering if (config->cfg.IsDefined("batch.halttime") && (config->cfg.GetInt("batch.halttime", 0) > 0)) throw runtime_error("batch.halttime parameter can not be used with batch.tile"); // image.subregion condition doesn't make sense in the context // of tile rendering if (config->cfg.IsDefined("image.subregion")) throw runtime_error("image.subregion parameter can not be used with batch.tile"); // Force the film update at 2.5secs (mostly used by PathOCL) config->SetScreenRefreshInterval(2500); const u_int filterBorder = 2; // Original film size const u_int originalFilmWidth = session->film->GetWidth(); const u_int originalFilmHeight = session->film->GetHeight(); // Allocate a film where to merge all tiles Film mergeTileFilm(originalFilmWidth, originalFilmWidth, session->film->HasPerPixelNormalizedBuffer(), session->film->HasPerScreenNormalizedBuffer(), true); mergeTileFilm.CopyDynamicSettings(*(session->film)); mergeTileFilm.EnableOverlappedScreenBufferUpdate(false); mergeTileFilm.Init(originalFilmWidth, originalFilmWidth); // Get the tile size vector<int> tileSize = config->cfg.GetIntVector("batch.tile", "256 256"); if (tileSize.size() != 2) throw runtime_error("Syntax error in batch.tile (required 2 parameters)"); tileSize[0] = Max<int>(64, Min<int>(tileSize[0], originalFilmWidth)); tileSize[1] = Max<int>(64, Min<int>(tileSize[1], originalFilmHeight)); SLG_LOG("Tile size: " << tileSize[0] << " x " << tileSize[1]); // Get the loop count int loopCount = config->cfg.GetInt("batch.tile.loops", 1); bool sessionStarted = false; for (int loopIndex = 0; loopIndex < loopCount; ++loopIndex) { u_int tileX = 0; u_int tileY = 0; const double startTime = WallClockTime(); // To setup new rendering parameters if (loopIndex > 0) { // I can begin an edit only after the start session->BeginEdit(); // I have to use a new seed or I will render exactly the same images session->renderEngine->GenerateNewSeed(); } for (;;) { SLG_LOG("Rendering tile offset: (" << tileX << "/" << originalFilmWidth + 2 * filterBorder << ", " << tileY << "/" << originalFilmHeight + 2 * filterBorder << ")"); // Set the film subregion to render u_int filmSubRegion[4]; filmSubRegion[0] = tileX; filmSubRegion[1] = Min(tileX + tileSize[0] - 1, originalFilmWidth - 1) + 2 * filterBorder; filmSubRegion[2] = tileY; filmSubRegion[3] = Min(tileY + tileSize[1] - 1, originalFilmHeight - 1) + 2 * filterBorder; SLG_LOG("Tile subregion: " << boost::lexical_cast<string>(filmSubRegion[0]) << " " << boost::lexical_cast<string>(filmSubRegion[1]) << " " << boost::lexical_cast<string>(filmSubRegion[2]) << " " << boost::lexical_cast<string>(filmSubRegion[3])); // Update the camera and resize the film session->renderConfig->scene->camera->Update( originalFilmWidth + 2 * filterBorder, originalFilmHeight + 2 * filterBorder, filmSubRegion); session->film->Init(session->renderConfig->scene->camera->GetFilmWeight(), session->renderConfig->scene->camera->GetFilmHeight()); if (sessionStarted) { session->editActions.AddAction(CAMERA_EDIT); session->editActions.AddAction(FILM_EDIT); session->EndEdit(); } else { session->Start(); sessionStarted = true; } double lastFilmUpdate = WallClockTime(); char buf[512]; for (;;) { boost::this_thread::sleep(boost::posix_time::millisec(1000)); // Film update may be required by some render engine to // update statistics, convergence test and more if (WallClockTime() - lastFilmUpdate > 5.0) { session->renderEngine->UpdateFilm(); lastFilmUpdate = WallClockTime(); } const unsigned int pass = engine->GetPass(); if ((haltSpp > 0) && (pass >= haltSpp)) break; // Convergence test is update inside UpdateFilm() const float convergence = engine->GetConvergence(); if ((haltThreshold >= 0.f) && (1.f - convergence <= haltThreshold)) break; // Print some information about the rendering progress const double now = WallClockTime(); const double elapsedTime = now - startTime; sprintf(buf, "[Loop step: %d/%d][Elapsed time: %3d][Samples %4d/%d][Convergence %f%%][Avg. samples/sec % 3.2fM on %.1fK tris]", loopIndex + 1, loopCount, int(elapsedTime), pass, haltSpp, 100.f * convergence, engine->GetTotalSamplesSec() / 1000000.0, config->scene->dataSet->GetTotalTriangleCount() / 1000.0); SLG_LOG(buf); } // Splat the current tile on the merge film session->renderEngine->UpdateFilm(); { boost::unique_lock<boost::mutex> lock(session->filmMutex); mergeTileFilm.AddFilm(*(session->film), filterBorder, filterBorder, filmSubRegion[1] - filmSubRegion[0] - 2 * filterBorder + 1, filmSubRegion[3] - filmSubRegion[2] - 2 * filterBorder + 1, tileX, tileY); } // Save the merge film const string fileName = config->cfg.GetString("image.filename", "image.png"); SLG_LOG("Saving merged tiles to: " << fileName); mergeTileFilm.UpdateScreenBuffer(); mergeTileFilm.SaveScreenBuffer(fileName); // Advance to the next tile tileX += tileSize[0]; if (tileX >= originalFilmWidth) { tileX = 0; tileY += tileSize[1]; if (tileY >= originalFilmHeight) { // Rendering done break; } } // To setup new rendering parameters session->BeginEdit(); } } // Stop the rendering session->Stop(); delete session; SLG_LOG("Done."); return EXIT_SUCCESS; }
void PathOCLRenderThread::InitRender() { Scene *scene = renderEngine->renderConfig->scene; cl::Context &oclContext = intersectionDevice->GetOpenCLContext(); cl::Device &oclDevice = intersectionDevice->GetOpenCLDevice(); const OpenCLDeviceDescription *deviceDesc = intersectionDevice->GetDeviceDesc(); double tStart, tEnd; //-------------------------------------------------------------------------- // FrameBuffer definition //-------------------------------------------------------------------------- InitFrameBuffer(); //-------------------------------------------------------------------------- // Camera definition //-------------------------------------------------------------------------- InitCamera(); //-------------------------------------------------------------------------- // Scene geometry //-------------------------------------------------------------------------- InitGeometry(); //-------------------------------------------------------------------------- // Translate material definitions //-------------------------------------------------------------------------- InitMaterials(); //-------------------------------------------------------------------------- // Translate area lights //-------------------------------------------------------------------------- InitAreaLights(); //-------------------------------------------------------------------------- // Check if there is an infinite light source //-------------------------------------------------------------------------- InitInfiniteLight(); //-------------------------------------------------------------------------- // Check if there is an sun light source //-------------------------------------------------------------------------- InitSunLight(); //-------------------------------------------------------------------------- // Check if there is an sky light source //-------------------------------------------------------------------------- InitSkyLight(); const unsigned int areaLightCount = renderEngine->compiledScene->areaLights.size(); if (!skyLightBuff && !sunLightBuff && !infiniteLightBuff && (areaLightCount == 0)) throw runtime_error("There are no light sources supported by PathOCL in the scene"); //-------------------------------------------------------------------------- // Translate mesh texture maps //-------------------------------------------------------------------------- InitTextureMaps(); //-------------------------------------------------------------------------- // Allocate Ray/RayHit buffers //-------------------------------------------------------------------------- const unsigned int taskCount = renderEngine->taskCount; tStart = WallClockTime(); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Ray buffer size: " << (sizeof(Ray) * taskCount / 1024) << "Kbytes"); raysBuff = new cl::Buffer(oclContext, CL_MEM_READ_WRITE, sizeof(Ray) * taskCount); deviceDesc->AllocMemory(raysBuff->getInfo<CL_MEM_SIZE>()); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] RayHit buffer size: " << (sizeof(RayHit) * taskCount / 1024) << "Kbytes"); hitsBuff = new cl::Buffer(oclContext, CL_MEM_READ_WRITE, sizeof(RayHit) * taskCount); deviceDesc->AllocMemory(hitsBuff->getInfo<CL_MEM_SIZE>()); tEnd = WallClockTime(); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] OpenCL buffer creation time: " << int((tEnd - tStart) * 1000.0) << "ms"); //-------------------------------------------------------------------------- // Allocate GPU task buffers //-------------------------------------------------------------------------- // TODO: clenup all this mess const size_t gpuTaksSizePart1 = // Seed size sizeof(PathOCL::Seed); const size_t uDataEyePathVertexSize = // IDX_SCREEN_X, IDX_SCREEN_Y sizeof(float) * 2 + // IDX_DOF_X, IDX_DOF_Y ((scene->camera->lensRadius > 0.f) ? (sizeof(float) * 2) : 0); const size_t uDataPerPathVertexSize = // IDX_TEX_ALPHA, ((texMapAlphaBuff) ? sizeof(float) : 0) + // IDX_BSDF_X, IDX_BSDF_Y, IDX_BSDF_Z sizeof(float) * 3 + // IDX_DIRECTLIGHT_X, IDX_DIRECTLIGHT_Y, IDX_DIRECTLIGHT_Z (((areaLightCount > 0) || sunLightBuff) ? (sizeof(float) * 3) : 0) + // IDX_RR sizeof(float); const size_t uDataSize = (renderEngine->sampler->type == PathOCL::INLINED_RANDOM) ? // Only IDX_SCREEN_X, IDX_SCREEN_Y (sizeof(float) * 2) : ((renderEngine->sampler->type == PathOCL::METROPOLIS) ? (sizeof(float) * 2 + sizeof(unsigned int) * 5 + sizeof(Spectrum) + 2 * (uDataEyePathVertexSize + uDataPerPathVertexSize * renderEngine->maxPathDepth)) : (uDataEyePathVertexSize + uDataPerPathVertexSize * renderEngine->maxPathDepth)); size_t sampleSize = // uint pixelIndex; ((renderEngine->sampler->type == PathOCL::METROPOLIS) ? 0 : sizeof(unsigned int)) + uDataSize + // Spectrum radiance; sizeof(Spectrum) + // float currentAlpha; (((renderEngine->sampler->type == PathOCL::METROPOLIS) && alphaFrameBufferBuff) ? sizeof(float) : 0); stratifiedDataSize = 0; if (renderEngine->sampler->type == PathOCL::STRATIFIED) { PathOCL::StratifiedSampler *s = (PathOCL::StratifiedSampler *)renderEngine->sampler; stratifiedDataSize = // stratifiedScreen2D sizeof(float) * s->xSamples * s->ySamples * 2 + // stratifiedDof2D ((scene->camera->lensRadius > 0.f) ? (sizeof(float) * s->xSamples * s->ySamples * 2) : 0) + // stratifiedAlpha1D ((texMapAlphaBuff) ? (sizeof(float) * s->xSamples) : 0) + // stratifiedBSDF2D sizeof(float) * s->xSamples * s->ySamples * 2 + // stratifiedBSDF1D sizeof(float) * s->xSamples + // stratifiedLight2D // stratifiedLight1D (((areaLightCount > 0) || sunLightBuff) ? (sizeof(float) * s->xSamples * s->ySamples * 2 + sizeof(float) * s->xSamples) : 0); sampleSize += stratifiedDataSize; } const size_t gpuTaksSizePart2 = sampleSize; const size_t gpuTaksSizePart3 = // PathState size (((areaLightCount > 0) || sunLightBuff) ? sizeof(PathOCL::PathStateDL) : sizeof(PathOCL::PathState)) + //unsigned int diffuseVertexCount; ((renderEngine->maxDiffusePathVertexCount < renderEngine->maxPathDepth) ? sizeof(unsigned int) : 0) + //uint vertexCount; //float alpha; (alphaFrameBufferBuff ? (sizeof(unsigned int) + sizeof(float)) : 0); const size_t gpuTaksSize = gpuTaksSizePart1 + gpuTaksSizePart2 + gpuTaksSizePart3; SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Size of a GPUTask: " << gpuTaksSize << "bytes (" << gpuTaksSizePart1 << " + " << gpuTaksSizePart2 << " + " << gpuTaksSizePart3 << ")"); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Tasks buffer size: " << (gpuTaksSize * taskCount / 1024) << "Kbytes"); // Check if the task buffer is too big if (oclDevice.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() < gpuTaksSize * taskCount) { stringstream ss; ss << "The GPUTask buffer is too big for this device (i.e. CL_DEVICE_MAX_MEM_ALLOC_SIZE=" << oclDevice.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() << "): try to reduce opencl.task.count and/or path.maxdepth and/or to change Sampler"; throw std::runtime_error(ss.str()); } tasksBuff = new cl::Buffer(oclContext, CL_MEM_READ_WRITE, gpuTaksSize * taskCount); deviceDesc->AllocMemory(tasksBuff->getInfo<CL_MEM_SIZE>()); //-------------------------------------------------------------------------- // Allocate GPU task statistic buffers //-------------------------------------------------------------------------- SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Task Stats buffer size: " << (sizeof(PathOCL::GPUTaskStats) * taskCount / 1024) << "Kbytes"); taskStatsBuff = new cl::Buffer(oclContext, CL_MEM_READ_WRITE, sizeof(PathOCL::GPUTaskStats) * taskCount); deviceDesc->AllocMemory(taskStatsBuff->getInfo<CL_MEM_SIZE>()); //-------------------------------------------------------------------------- // Compile kernels //-------------------------------------------------------------------------- InitKernels(); //-------------------------------------------------------------------------- // Initialize //-------------------------------------------------------------------------- // Set kernel arguments SetKernelArgs(); cl::CommandQueue &oclQueue = intersectionDevice->GetOpenCLQueue(); // Clear the frame buffer oclQueue.enqueueNDRangeKernel(*initFBKernel, cl::NullRange, cl::NDRange(RoundUp<unsigned int>(frameBufferPixelCount, initFBWorkGroupSize)), cl::NDRange(initFBWorkGroupSize)); // Initialize the tasks buffer oclQueue.enqueueNDRangeKernel(*initKernel, cl::NullRange, cl::NDRange(taskCount), cl::NDRange(initWorkGroupSize)); oclQueue.finish(); // Reset statistics in order to be more accurate intersectionDevice->ResetPerformaceStats(); }
void PathOCLRenderThread::InitKernels() { //-------------------------------------------------------------------------- // Compile kernels //-------------------------------------------------------------------------- CompiledScene *cscene = renderEngine->compiledScene; cl::Context &oclContext = intersectionDevice->GetOpenCLContext(); cl::Device &oclDevice = intersectionDevice->GetOpenCLDevice(); // Set #define symbols stringstream ss; ss.precision(6); ss << scientific << " -D PARAM_TASK_COUNT=" << renderEngine->taskCount << " -D PARAM_IMAGE_WIDTH=" << renderEngine->film->GetWidth() << " -D PARAM_IMAGE_HEIGHT=" << renderEngine->film->GetHeight() << " -D PARAM_RAY_EPSILON=" << renderEngine->epsilon << "f" << " -D PARAM_SEED=" << seed << " -D PARAM_MAX_PATH_DEPTH=" << renderEngine->maxPathDepth << " -D PARAM_MAX_DIFFUSE_PATH_VERTEX_COUNT=" << renderEngine->maxDiffusePathVertexCount << " -D PARAM_RR_DEPTH=" << renderEngine->rrDepth << " -D PARAM_RR_CAP=" << renderEngine->rrImportanceCap << "f" ; switch (renderEngine->renderConfig->scene->dataSet->GetAcceleratorType()) { case ACCEL_BVH: ss << " -D PARAM_ACCEL_BVH"; break; case ACCEL_QBVH: ss << " -D PARAM_ACCEL_QBVH"; break; case ACCEL_MQBVH: ss << " -D PARAM_ACCEL_MQBVH"; break; default: assert (false); } if (cscene->enable_MAT_MATTE) ss << " -D PARAM_ENABLE_MAT_MATTE"; if (cscene->enable_MAT_AREALIGHT) ss << " -D PARAM_ENABLE_MAT_AREALIGHT"; if (cscene->enable_MAT_MIRROR) ss << " -D PARAM_ENABLE_MAT_MIRROR"; if (cscene->enable_MAT_GLASS) ss << " -D PARAM_ENABLE_MAT_GLASS"; if (cscene->enable_MAT_MATTEMIRROR) ss << " -D PARAM_ENABLE_MAT_MATTEMIRROR"; if (cscene->enable_MAT_METAL) ss << " -D PARAM_ENABLE_MAT_METAL"; if (cscene->enable_MAT_MATTEMETAL) ss << " -D PARAM_ENABLE_MAT_MATTEMETAL"; if (cscene->enable_MAT_ALLOY) ss << " -D PARAM_ENABLE_MAT_ALLOY"; if (cscene->enable_MAT_ARCHGLASS) ss << " -D PARAM_ENABLE_MAT_ARCHGLASS"; if (cscene->camera.lensRadius > 0.f) ss << " -D PARAM_CAMERA_HAS_DOF"; if (infiniteLightBuff) ss << " -D PARAM_HAS_INFINITELIGHT"; if (skyLightBuff) ss << " -D PARAM_HAS_SKYLIGHT"; if (sunLightBuff) { ss << " -D PARAM_HAS_SUNLIGHT"; if (!areaLightsBuff) { ss << " -D PARAM_DIRECT_LIGHT_SAMPLING" << " -D PARAM_DL_LIGHT_COUNT=0" ; } } if (areaLightsBuff) { ss << " -D PARAM_DIRECT_LIGHT_SAMPLING" << " -D PARAM_DL_LIGHT_COUNT=" << renderEngine->compiledScene->areaLights.size() ; } if (texMapRGBBuff || texMapAlphaBuff) ss << " -D PARAM_HAS_TEXTUREMAPS"; if (texMapAlphaBuff) ss << " -D PARAM_HAS_ALPHA_TEXTUREMAPS"; if (meshBumpsBuff) ss << " -D PARAM_HAS_BUMPMAPS"; if (meshNormalMapsBuff) ss << " -D PARAM_HAS_NORMALMAPS"; const PathOCL::Filter *filter = renderEngine->filter; switch (filter->type) { case PathOCL::NONE: ss << " -D PARAM_IMAGE_FILTER_TYPE=0"; break; case PathOCL::BOX: ss << " -D PARAM_IMAGE_FILTER_TYPE=1" << " -D PARAM_IMAGE_FILTER_WIDTH_X=" << filter->widthX << "f" << " -D PARAM_IMAGE_FILTER_WIDTH_Y=" << filter->widthY << "f"; break; case PathOCL::GAUSSIAN: ss << " -D PARAM_IMAGE_FILTER_TYPE=2" << " -D PARAM_IMAGE_FILTER_WIDTH_X=" << filter->widthX << "f" << " -D PARAM_IMAGE_FILTER_WIDTH_Y=" << filter->widthY << "f" << " -D PARAM_IMAGE_FILTER_GAUSSIAN_ALPHA=" << ((PathOCL::GaussianFilter *)filter)->alpha << "f"; break; case PathOCL::MITCHELL: ss << " -D PARAM_IMAGE_FILTER_TYPE=3" << " -D PARAM_IMAGE_FILTER_WIDTH_X=" << filter->widthX << "f" << " -D PARAM_IMAGE_FILTER_WIDTH_Y=" << filter->widthY << "f" << " -D PARAM_IMAGE_FILTER_MITCHELL_B=" << ((PathOCL::MitchellFilter *)filter)->B << "f" << " -D PARAM_IMAGE_FILTER_MITCHELL_C=" << ((PathOCL::MitchellFilter *)filter)->C << "f"; break; default: assert (false); } if (renderEngine->usePixelAtomics) ss << " -D PARAM_USE_PIXEL_ATOMICS"; const PathOCL::Sampler *sampler = renderEngine->sampler; switch (sampler->type) { case PathOCL::INLINED_RANDOM: ss << " -D PARAM_SAMPLER_TYPE=0"; break; case PathOCL::RANDOM: ss << " -D PARAM_SAMPLER_TYPE=1"; break; case PathOCL::METROPOLIS: ss << " -D PARAM_SAMPLER_TYPE=2" << " -D PARAM_SAMPLER_METROPOLIS_LARGE_STEP_RATE=" << ((PathOCL::MetropolisSampler *)sampler)->largeStepRate << "f" << " -D PARAM_SAMPLER_METROPOLIS_MAX_CONSECUTIVE_REJECT=" << ((PathOCL::MetropolisSampler *)sampler)->maxConsecutiveReject << " -D PARAM_SAMPLER_METROPOLIS_IMAGE_MUTATION_RANGE=" << ((PathOCL::MetropolisSampler *)sampler)->imageMutationRate << "f"; break; case PathOCL::STRATIFIED: ss << " -D PARAM_SAMPLER_TYPE=3" << " -D PARAM_SAMPLER_STRATIFIED_X_SAMPLES=" << ((PathOCL::StratifiedSampler *)sampler)->xSamples << " -D PARAM_SAMPLER_STRATIFIED_Y_SAMPLES=" << ((PathOCL::StratifiedSampler *)sampler)->ySamples; break; default: assert (false); } if (renderEngine->film->IsAlphaChannelEnabled()) ss << " -D PARAM_ENABLE_ALPHA_CHANNEL"; // Check the OpenCL vendor and use some specific compiler options #if defined(__APPLE__) // OSX version detection { struct utsname retval; uname(&retval); if(retval.release[0] == '1' && retval.release[1] < '1') // result < darwin 11 ss << " -D __APPLE_FIX__"; } #endif //-------------------------------------------------------------------------- const double tStart = WallClockTime(); // Check if I have to recompile the kernels string newKernelParameters = ss.str(); if (kernelsParameters != newKernelParameters) { kernelsParameters = newKernelParameters; // Compile sources stringstream ssKernel; ssKernel << _LUXRAYS_UV_OCLDEFINE _LUXRAYS_SPECTRUM_OCLDEFINE _LUXRAYS_POINT_OCLDEFINE _LUXRAYS_VECTOR_OCLDEFINE _LUXRAYS_TRIANGLE_OCLDEFINE _LUXRAYS_RAY_OCLDEFINE _LUXRAYS_RAYHIT_OCLDEFINE << KernelSource_PathOCL_kernel_datatypes << KernelSource_PathOCL_kernel_core << KernelSource_PathOCL_kernel_filters << KernelSource_PathOCL_kernel_scene << KernelSource_PathOCL_kernel_samplers << KernelSource_PathOCL_kernels; string kernelSource = ssKernel.str(); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Defined symbols: " << kernelsParameters); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Compiling kernels "); bool cached; cl::STRING_CLASS error; cl::Program *program = kernelCache->Compile(oclContext, oclDevice, kernelsParameters, kernelSource, &cached, &error); if (!program) { SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] PathOCL kernel compilation error" << std::endl << error); throw std::runtime_error("PathOCL kernel compilation error"); } if (cached) { SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Kernels cached"); } else { SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Kernels not cached"); } //---------------------------------------------------------------------- // Init kernel //---------------------------------------------------------------------- delete initKernel; SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Compiling Init Kernel"); initKernel = new cl::Kernel(*program, "Init"); initKernel->getWorkGroupInfo<size_t>(oclDevice, CL_KERNEL_WORK_GROUP_SIZE, &initWorkGroupSize); if (intersectionDevice->GetForceWorkGroupSize() > 0) initWorkGroupSize = intersectionDevice->GetForceWorkGroupSize(); else if (renderEngine->sampler->type == PathOCL::STRATIFIED) { // Resize the workgroup to have enough local memory size_t localMem = oclDevice.getInfo<CL_DEVICE_LOCAL_MEM_SIZE>(); while ((initWorkGroupSize > 64) && (stratifiedDataSize * initWorkGroupSize > localMem)) initWorkGroupSize /= 2; if (stratifiedDataSize * initWorkGroupSize > localMem) throw std::runtime_error("Not enough local memory to run, try to reduce path.sampler.xsamples and path.sampler.xsamples values"); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Cap work group size to: " << initWorkGroupSize); } //-------------------------------------------------------------------------- // InitFB kernel //-------------------------------------------------------------------------- delete initFBKernel; initFBKernel = new cl::Kernel(*program, "InitFrameBuffer"); initFBKernel->getWorkGroupInfo<size_t>(oclDevice, CL_KERNEL_WORK_GROUP_SIZE, &initFBWorkGroupSize); if (intersectionDevice->GetForceWorkGroupSize() > 0) initFBWorkGroupSize = intersectionDevice->GetForceWorkGroupSize(); //---------------------------------------------------------------------- // Sampler kernel //---------------------------------------------------------------------- delete samplerKernel; SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Compiling Sampler Kernel"); samplerKernel = new cl::Kernel(*program, "Sampler"); samplerKernel->getWorkGroupInfo<size_t>(oclDevice, CL_KERNEL_WORK_GROUP_SIZE, &samplerWorkGroupSize); if (intersectionDevice->GetForceWorkGroupSize() > 0) samplerWorkGroupSize = intersectionDevice->GetForceWorkGroupSize(); else if (renderEngine->sampler->type == PathOCL::STRATIFIED) { // Resize the workgroup to have enough local memory size_t localMem = oclDevice.getInfo<CL_DEVICE_LOCAL_MEM_SIZE>(); while ((samplerWorkGroupSize > 64) && (stratifiedDataSize * samplerWorkGroupSize > localMem)) samplerWorkGroupSize /= 2; if (stratifiedDataSize * samplerWorkGroupSize > localMem) throw std::runtime_error("Not enough local memory to run, try to reduce path.sampler.xsamples and path.sampler.xsamples values"); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Cap work group size to: " << samplerWorkGroupSize); } //---------------------------------------------------------------------- // AdvancePaths kernel //---------------------------------------------------------------------- delete advancePathsKernel; SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Compiling AdvancePaths Kernel"); advancePathsKernel = new cl::Kernel(*program, "AdvancePaths"); advancePathsKernel->getWorkGroupInfo<size_t>(oclDevice, CL_KERNEL_WORK_GROUP_SIZE, &advancePathsWorkGroupSize); if (intersectionDevice->GetForceWorkGroupSize() > 0) advancePathsWorkGroupSize = intersectionDevice->GetForceWorkGroupSize(); //---------------------------------------------------------------------- const double tEnd = WallClockTime(); SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Kernels compilation time: " << int((tEnd - tStart) * 1000.0) << "ms"); delete program; } else SLG_LOG("[PathOCLRenderThread::" << threadIndex << "] Using cached kernels"); }
void PathOCLRenderThread::RenderThreadImpl(PathOCLRenderThread *renderThread) { //SLG_LOG("[PathOCLRenderThread::" << renderThread->threadIndex << "] Rendering thread started"); cl::CommandQueue &oclQueue = renderThread->intersectionDevice->GetOpenCLQueue(); const unsigned int taskCount = renderThread->renderEngine->taskCount; try { double startTime = WallClockTime(); while (!boost::this_thread::interruption_requested()) { /*if(renderThread->threadIndex == 0) cerr<< "[DEBUG] =================================");*/ // Async. transfer of the frame buffer oclQueue.enqueueReadBuffer( *(renderThread->frameBufferBuff), CL_FALSE, 0, renderThread->frameBufferBuff->getInfo<CL_MEM_SIZE>(), renderThread->frameBuffer); // Check if I have to transfer the alpha channel too if (renderThread->alphaFrameBufferBuff) { // Async. transfer of the alpha channel oclQueue.enqueueReadBuffer( *(renderThread->alphaFrameBufferBuff), CL_FALSE, 0, renderThread->alphaFrameBufferBuff->getInfo<CL_MEM_SIZE>(), renderThread->alphaFrameBuffer); } // Async. transfer of GPU task statistics oclQueue.enqueueReadBuffer( *(renderThread->taskStatsBuff), CL_FALSE, 0, sizeof(PathOCL::GPUTaskStats) * taskCount, renderThread->gpuTaskStats); for (;;) { cl::Event event; // Decide how many kernels to enqueue const unsigned int screenRefreshInterval = renderThread->renderEngine->renderConfig->GetScreenRefreshInterval(); unsigned int iterations; if (screenRefreshInterval <= 100) iterations = 1; else if (screenRefreshInterval <= 500) iterations = 2; else if (screenRefreshInterval <= 1000) iterations = 4; else iterations = 8; for (unsigned int i = 0; i < iterations; ++i) { // Generate the samples and paths if (i == 0) oclQueue.enqueueNDRangeKernel(*(renderThread->samplerKernel), cl::NullRange, cl::NDRange(taskCount), cl::NDRange(renderThread->samplerWorkGroupSize), NULL, &event); else oclQueue.enqueueNDRangeKernel(*(renderThread->samplerKernel), cl::NullRange, cl::NDRange(taskCount), cl::NDRange(renderThread->samplerWorkGroupSize)); // Trace rays renderThread->intersectionDevice->EnqueueTraceRayBuffer(*(renderThread->raysBuff), *(renderThread->hitsBuff), taskCount, NULL, NULL); // Advance to next path state oclQueue.enqueueNDRangeKernel(*(renderThread->advancePathsKernel), cl::NullRange, cl::NDRange(taskCount), cl::NDRange(renderThread->advancePathsWorkGroupSize)); } oclQueue.flush(); event.wait(); const double elapsedTime = WallClockTime() - startTime; /*if(renderThread->threadIndex == 0) cerr<< "[DEBUG] Elapsed time: " << elapsedTime * 1000.0 << "ms (screenRefreshInterval: " << renderThread->renderEngine->screenRefreshInterval << ")");*/ if ((elapsedTime * 1000.0 > (double)screenRefreshInterval) || boost::this_thread::interruption_requested()) break; } startTime = WallClockTime(); } //SLG_LOG("[PathOCLRenderThread::" << renderThread->threadIndex << "] Rendering thread halted"); } catch (boost::thread_interrupted) { SLG_LOG("[PathOCLRenderThread::" << renderThread->threadIndex << "] Rendering thread halted"); } catch (cl::Error err) { SLG_LOG("[PathOCLRenderThread::" << renderThread->threadIndex << "] Rendering thread ERROR: " << err.what() << "(" << luxrays::utils::oclErrorString(err.err()) << ")"); } oclQueue.enqueueReadBuffer( *(renderThread->frameBufferBuff), CL_TRUE, 0, renderThread->frameBufferBuff->getInfo<CL_MEM_SIZE>(), renderThread->frameBuffer); // Check if I have to transfer the alpha channel too if (renderThread->alphaFrameBufferBuff) { oclQueue.enqueueReadBuffer( *(renderThread->alphaFrameBufferBuff), CL_TRUE, 0, renderThread->alphaFrameBufferBuff->getInfo<CL_MEM_SIZE>(), renderThread->alphaFrameBuffer); } }
void keyFunc(unsigned char key, int x, int y) { switch (key) { case 'p': { session->SaveFilmImage(); break; } case 27: { // Escape key delete session; SLG_LOG("Done."); exit(EXIT_SUCCESS); break; } case ' ': // Restart rendering session->Stop(); session->Start(); break; case 'a': { session->BeginEdit(); session->renderConfig->scene->camera->TranslateLeft(MOVE_STEP); session->renderConfig->scene->camera->Update( session->film->GetWidth(), session->film->GetHeight()); session->editActions.AddAction(CAMERA_EDIT); session->EndEdit(); break; } case 'd': { session->BeginEdit(); session->renderConfig->scene->camera->TranslateRight(MOVE_STEP); session->renderConfig->scene->camera->Update( session->film->GetWidth(), session->film->GetHeight()); session->editActions.AddAction(CAMERA_EDIT); session->EndEdit(); break; } case 'w': { session->BeginEdit(); session->renderConfig->scene->camera->TranslateForward(MOVE_STEP); session->renderConfig->scene->camera->Update( session->film->GetWidth(), session->film->GetHeight()); session->editActions.AddAction(CAMERA_EDIT); session->EndEdit(); break; } case 's': { session->BeginEdit(); session->renderConfig->scene->camera->TranslateBackward(MOVE_STEP); session->renderConfig->scene->camera->Update( session->film->GetWidth(), session->film->GetHeight()); session->editActions.AddAction(CAMERA_EDIT); session->EndEdit(); break; } case 'r': session->BeginEdit(); session->renderConfig->scene->camera->Translate(Vector(0.f, 0.f, MOVE_STEP)); session->renderConfig->scene->camera->Update( session->film->GetWidth(), session->film->GetHeight()); session->editActions.AddAction(CAMERA_EDIT); session->EndEdit(); break; case 'f': session->BeginEdit(); session->renderConfig->scene->camera->Translate(Vector(0.f, 0.f, -MOVE_STEP)); session->renderConfig->scene->camera->Update( session->film->GetWidth(), session->film->GetHeight()); session->editActions.AddAction(CAMERA_EDIT); session->EndEdit(); break; case 'h': OSDPrintHelp = (!OSDPrintHelp); break; case 'n': { const unsigned int screenRefreshInterval = session->renderConfig->GetScreenRefreshInterval(); if (screenRefreshInterval > 1000) session->renderConfig->SetScreenRefreshInterval(max(1000u, screenRefreshInterval - 1000)); else session->renderConfig->SetScreenRefreshInterval(max(50u, screenRefreshInterval - 50)); break; } case 'm': { const unsigned int screenRefreshInterval = session->renderConfig->GetScreenRefreshInterval(); if (screenRefreshInterval >= 1000) session->renderConfig->SetScreenRefreshInterval(screenRefreshInterval + 1000); else session->renderConfig->SetScreenRefreshInterval(screenRefreshInterval + 50); break; } case 't': // Toggle tonemap type if (session->film->GetToneMapParams()->GetType() == TONEMAP_LINEAR) { Reinhard02ToneMapParams params; session->film->SetToneMapParams(params); } else { LinearToneMapParams params; session->film->SetToneMapParams(params); } break; /*case '0': config->SetRenderingEngineType(PATHOCL); glutTimerFunc(config->GetScreenRefreshInterval(), timerFunc, 0); break;*/ case 'o': { #if defined(WIN32) std::wstring ws; ws.assign(SLG_LABEL.begin (), SLG_LABEL.end()); HWND hWnd = FindWindowW(NULL, ws.c_str()); if (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) SetWindowPos(hWnd, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); else SetWindowPos(hWnd, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); #endif break; } default: break; } displayFunc(); }