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));
	}
}
示例#5
0
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>());
}
示例#6
0
void RenderSession::EndEdit() {
	assert (started);
	assert (editMode);

	if (editActions.Size() > 0)
		film->Reset();

	SLG_LOG("[RenderSession] Edit actions: " << editActions);
	renderEngine->EndEdit(editActions);
	editMode = false;
}
示例#7
0
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;
}
示例#12
0
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();
}
示例#13
0
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");
}
示例#14
0
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);
	}
}
示例#15
0
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();
}