/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "DLLInterface.h"
#include "Pimpl.h"
#include "CudaDevice.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx.LFR
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	namespace LFR
	{
		class CCuda_Impl;

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Provides information about the CUDA hardware in your system and enables access to available CUDA devices.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class RX_API CCuda : public CPimpl<CCuda_Impl, Interfaces::ECuda::ID>
		{
		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Enumerates and stores all CUDA devices.
			/// </summary>
			///
			/// <returns> The number of available CUDA devices. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static int EnumerateCudaDevices();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the number of available CUDA devices in your system.
			/// </summary>
			///
			/// <returns> The number of available CUDA devices. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static int GetDeviceCount();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets a certain CUDA device.
			/// </summary>
			///
			/// <param name="iIdx"> The index of the CUDA device. Must be in the range of [0, GetDeviceCount() - 1]. </param>
			///
			/// <returns> The CUDA device. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static const CCudaDevice& GetDevice(int iIdx);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the installed CUDA runtime version.
			/// </summary>
			///
			/// <returns> The runtime version. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static int GetRuntimeVersion();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the installed CUDA driver version. Returns 0 if there is no CUDA driver installed.
			/// </summary>
			///
			/// <returns> The driver version. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static int GetDriverVersion();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Forces an immediate garbage collection of temporary CUDA memory.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GC_Collect();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Finalizes CUDA. This finalizes all CUDA devices.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void End();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the interface defined by Interfaces::ECuda.
			/// </summary>
			///
			/// <param name="eData"> The interface type. </param>
			///
			/// <returns> Null if it fails, else the interface. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void* GetInterface(Interfaces::ECuda::ID eData);

		private:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CCuda();
			~CCuda();
			CCuda(const CCuda&);
			CCuda& operator=(const CCuda&);
		};
	}
}
