void OpenCLIntersectionDevice::IntersectionThread(OpenCLIntersectionDevice *renderDevice) {
	LR_LOG(renderDevice->deviceContext, "[OpenCL device::" << renderDevice->deviceName << "] Rendering thread started");

	try {
		RayBufferQueue *queue = renderDevice->externalRayBufferQueue ?
			renderDevice->externalRayBufferQueue : &(renderDevice->rayBufferQueue);

		RayBuffer *rayBuffer0, *rayBuffer1, *rayBuffer2;
		const double startTime = WallClockTime();
		while (!boost::this_thread::interruption_requested()) {
			const double t1 = WallClockTime();
			queue->Pop3xToDo(&rayBuffer0, &rayBuffer1, &rayBuffer2);
			renderDevice->statsDeviceIdleTime += WallClockTime() - t1;
			const unsigned int count = (rayBuffer0 ? 1 : 0) + (rayBuffer1 ? 1 : 0) + (rayBuffer2 ? 1 : 0);

			switch(count) {
				case 1: {
					// Only one ray buffer to trace available
					VECTOR_CLASS<cl::Event> readEvent0(1);
					VECTOR_CLASS<cl::Event> traceEvent0(1);
					cl::Event event0;
					renderDevice->TraceRayBuffer(rayBuffer0,
						readEvent0, traceEvent0,
						&event0);

					event0.wait();
					queue->PushDone(rayBuffer0);

					renderDevice->statsDeviceTotalTime = WallClockTime() - startTime;
					break;
				}
				case 2: {
					// At least 2 ray buffers to trace

					// Trace 0 ray buffer
					VECTOR_CLASS<cl::Event> readEvent0(1);
					VECTOR_CLASS<cl::Event> traceEvent0(1);
					cl::Event event0;
					renderDevice->TraceRayBuffer(rayBuffer0,
						readEvent0, traceEvent0,
						&event0);

					// Trace 1 ray buffer
					VECTOR_CLASS<cl::Event> readEvent1(1);
					VECTOR_CLASS<cl::Event> traceEvent1(1);
					cl::Event event1;
					renderDevice->TraceRayBuffer(rayBuffer1,
						readEvent1, traceEvent1,
						&event1);

					// Pop 0 ray buffer
					event0.wait();
					queue->PushDone(rayBuffer0);

					// Pop 1 ray buffer
					event1.wait();
					queue->PushDone(rayBuffer1);

					renderDevice->statsDeviceTotalTime = WallClockTime() - startTime;
					break;
				}
				case 3: {
					// At least 3 ray buffers to trace

					// Trace 0 ray buffer
					VECTOR_CLASS<cl::Event> readEvent0(1);
					VECTOR_CLASS<cl::Event> traceEvent0(1);
					cl::Event event0;
					renderDevice->TraceRayBuffer(rayBuffer0,
						readEvent0, traceEvent0,
						&event0);

					// Trace 1 ray buffer
					VECTOR_CLASS<cl::Event> readEvent1(1);
					VECTOR_CLASS<cl::Event> traceEvent1(1);
					cl::Event event1;
					renderDevice->TraceRayBuffer(rayBuffer1,
						readEvent1, traceEvent1,
						&event1);

					// Trace 2 ray buffer
					VECTOR_CLASS<cl::Event> readEvent2(1);
					VECTOR_CLASS<cl::Event> traceEvent2(1);
					cl::Event event2;
					renderDevice->TraceRayBuffer(rayBuffer2,
						readEvent2, traceEvent2,
						&event2);

					// Pop 0 ray buffer
					event0.wait();
					queue->PushDone(rayBuffer0);

					// Pop 1 ray buffer
					event1.wait();
					queue->PushDone(rayBuffer1);

					// Pop 2 ray buffer
					event2.wait();
					queue->PushDone(rayBuffer2);

					renderDevice->statsDeviceTotalTime = WallClockTime() - startTime;
					break;
				}
				default:
					assert (false);
			}
		}

		LR_LOG(renderDevice->deviceContext, "[OpenCL device::" << renderDevice->deviceName << "] Rendering thread halted");
	} catch (boost::thread_interrupted) {
		LR_LOG(renderDevice->deviceContext, "[OpenCL device::" << renderDevice->deviceName << "] Rendering thread halted");
	} catch (cl::Error err) {
		LR_LOG(renderDevice->deviceContext, "[OpenCL device::" << renderDevice->deviceName << "] Rendering thread ERROR: " << err.what() << "(" << luxrays::utils::oclErrorString(err.err()) << ")");
	}
}