#include "CUDANormalizedConvolutionRImageFilter.h"

#include "ritkCudaMacros.h"


//#define GPU_RUNTIME

//----------------------------------------------------------------------------
template<class TRImage>
CUDANormalizedConvolutionRImageFilter<TRImage>
::CUDANormalizedConvolutionRImageFilter()
{
	// Instantiate the actual filter operating on the range data
	m_RangeFilter = RangeFilterType::New();

#ifdef GPU_RUNTIME
	this->SetAutoTimerMode(false);
#endif
}


//----------------------------------------------------------------------------
template<class TRImage>
CUDANormalizedConvolutionRImageFilter<TRImage>
::~CUDANormalizedConvolutionRImageFilter()
{
}


//----------------------------------------------------------------------------
template<class TRImage>
void
CUDANormalizedConvolutionRImageFilter<TRImage>
::SetRangeSigma(float Sigma)
{
	// Simply delegate the parameter to the filter operating on the range data
	this->m_RangeFilter->SetSigma(Sigma);
}


//----------------------------------------------------------------------------
template<class TRImage>
void
CUDANormalizedConvolutionRImageFilter<TRImage>
::SetRangeKernelSize(int Size)
{
	// Simply delegate the parameter to the filter operating on the range data
	this->m_RangeFilter->SetKernelSize(Size);
}


//----------------------------------------------------------------------------
template<class TRImage>
void
CUDANormalizedConvolutionRImageFilter<TRImage>
::DoFiltering()
{
#ifdef GPU_RUNTIME
	// Create timer on the default stream
	cudaEvent_t start_event, stop_event;
    ritkCudaSafeCall(cudaEventCreateWithFlags(&start_event, cudaEventBlockingSync));
    ritkCudaSafeCall(cudaEventCreateWithFlags(&stop_event, cudaEventBlockingSync));
	cudaEventRecord(start_event, 0);
#endif

	// Only filter range data
	if ( (Superclass::GetFilterMode()&Superclass::RANGE) == Superclass::RANGE )
	{
		try
		{
			// Set the input
			m_RangeFilter->SetInput(this->GetInput()->GetRangeImage());	
			m_RangeFilter->SetMaskImageInput(this->GetInput()->GetFlagImage());

			// Update the filter
			m_RangeFilter->UpdateLargestPossibleRegion();

			// Set the output
			this->GetOutput()->GetRangeImage()->Graft(m_RangeFilter->GetOutput());
			this->GetOutput()->GetFlagImage()->Graft(m_RangeFilter->GetMaskImageOutput());
		}
		catch ( itk::ExceptionObject &e )
		{
			std::cerr << e << std::endl;
		}
	}

#ifdef GPU_RUNTIME
	// Compute elapsed time
	cudaEventRecord(stop_event, 0);
    cudaEventSynchronize(stop_event);   
	float Time = 0;
    ritkCudaSafeCall(cudaEventElapsedTime(&Time, start_event, stop_event));
	cudaEventDestroy(start_event);
	cudaEventDestroy(stop_event);
	this->AddElapsedTime(Time/1000.0);
#endif

	// Due to fps evaluation
	//cudaThreadSynchronize();
}
