#ifndef EZT_CUDA_H
#define EZT_CUDA_H
extern "C" {

#include <cuda.h>
#include "cuda_ev_codes.h"
#include "eztrace.h"


  /**** CUDA runtime interface ****/

  extern  cudaError_t (*libcudaDeviceSynchronize)();
  extern  cudaError_t (*libcudaThreadSynchronize)(); // note: deprecated

  /* Kernel management */
  extern  cudaError_t (*libcudaLaunch)(const void *func);
  extern  cudaError_t (*libcudaConfigureCall) ( dim3  gridDim, dim3  blockDim, size_t  sharedMem, cudaStream_t  stream );

  /* Memory management */
  extern  cudaError_t  (*libcudaMalloc)(void **devPtr, size_t size);
  extern  cudaError_t  (*libcudaMallocHost)(void **ptr, size_t size);
  extern  cudaError_t  (*libcudaMallocPitch)(void **devPtr, size_t *pitch, size_t width, size_t height);
  extern  cudaError_t  (*libcudaMallocArray)(struct cudaArray **array, const struct cudaChannelFormatDesc *desc, size_t width, size_t height, unsigned int flags);
  extern  cudaError_t  (*libcudaMalloc3D)(struct cudaPitchedPtr* pitchedDevPtr, struct cudaExtent extent);
  extern  cudaError_t  (*libcudaMalloc3DArray)(cudaArray_t *array, const struct cudaChannelFormatDesc* desc, struct cudaExtent extent, unsigned int flags);
  extern  cudaError_t  (*libcudaMallocMipmappedArray)(cudaMipmappedArray_t *mipmappedArray, const struct cudaChannelFormatDesc* desc, struct cudaExtent extent, unsigned int numLevels, unsigned int flags);
  extern  cudaError_t  (*libcudaFree)(void *devPtr);
  extern  cudaError_t  (*libcudaFreeHost)(void *ptr);
  extern  cudaError_t  (*libcudaFreeArray)(cudaArray_t array);
  extern  cudaError_t  (*libcudaFreeMipmappedArray)(cudaMipmappedArray_t mipmappedArray);

  extern  cudaError_t  (*libcudaHostAlloc)(void **pHost, size_t size, unsigned int flags);
  extern  cudaError_t  (*libcudaHostRegister)(void *ptr, size_t size, unsigned int flags);
  extern  cudaError_t  (*libcudaHostUnregister)(void *ptr);


  /* Memory Transfers */
  extern  cudaError_t  (*libcudaMemcpy3D)(const struct cudaMemcpy3DParms *p);
  extern  cudaError_t  (*libcudaMemcpy3DPeer)(const struct cudaMemcpy3DPeerParms *p);
  extern  cudaError_t  (*libcudaMemcpy3DAsync)(const struct cudaMemcpy3DParms *p, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpy3DPeerAsync)(const struct cudaMemcpy3DPeerParms *p, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpy)(void *dst, const void *src, size_t count, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpyPeer)(void *dst, int dstDevice, const void *src, int srcDevice, size_t count);
  extern  cudaError_t  (*libcudaMemcpyToArray)(cudaArray_t dst, size_t wOffset, size_t hOffset, const void *src, size_t count, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpyFromArray)(void *dst, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t count, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpyArrayToArray)(cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t count, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpy2D)(void *dst, size_t dpitch, const void *src, size_t spitch, size_t width, size_t height, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpy2DToArray)(cudaArray_t dst, size_t wOffset, size_t hOffset, const void *src, size_t spitch, size_t width, size_t height, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpy2DFromArray)(void *dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpy2DArrayToArray)(cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpyToSymbol)(const void *symbol, const void *src, size_t count, size_t offset , enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpyFromSymbol)(void *dst, const void *symbol, size_t count, size_t offset , enum cudaMemcpyKind kind);
  extern  cudaError_t  (*libcudaMemcpyAsync)(void *dst, const void *src, size_t count, enum cudaMemcpyKind kind, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpyPeerAsync)(void *dst, int dstDevice, const void *src, int srcDevice, size_t count, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpyToArrayAsync)(cudaArray_t dst, size_t wOffset, size_t hOffset, const void *src, size_t count, enum cudaMemcpyKind kind, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpyFromArrayAsync)(void *dst, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t count, enum cudaMemcpyKind kind, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpy2DAsync)(void *dst, size_t dpitch, const void *src, size_t spitch, size_t width, size_t height, enum cudaMemcpyKind kind, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpy2DToArrayAsync)(cudaArray_t dst, size_t wOffset, size_t hOffset, const void *src, size_t spitch, size_t width, size_t height, enum cudaMemcpyKind kind, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpy2DFromArrayAsync)(void *dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, enum cudaMemcpyKind kind, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpyToSymbolAsync)(const void *symbol, const void *src, size_t count, size_t offset, enum cudaMemcpyKind kind, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemcpyFromSymbolAsync)(void *dst, const void *symbol, size_t count, size_t offset, enum cudaMemcpyKind kind, cudaStream_t stream );

  extern  cudaError_t  (*libcudaMemset)(void *devPtr, int value, size_t count);
  extern  cudaError_t  (*libcudaMemset2D)(void *devPtr, size_t pitch, int value, size_t width, size_t height);
  extern  cudaError_t  (*libcudaMemset3D)(struct cudaPitchedPtr pitchedDevPtr, int value, struct cudaExtent extent);
  extern  cudaError_t  (*libcudaMemsetAsync)(void *devPtr, int value, size_t count, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemset2DAsync)(void *devPtr, size_t pitch, int value, size_t width, size_t height, cudaStream_t stream );
  extern  cudaError_t  (*libcudaMemset3DAsync)(struct cudaPitchedPtr pitchedDevPtr, int value, struct cudaExtent extent, cudaStream_t stream );



  /**** CUDA driver interface ****/

#if 0
  extern  CUresult (*libcuMemcpyAtoA_v2)(CUarray dstArray, size_t dstOffset, CUarray srcArray, size_t srcOffset, size_t ByteCount);
  extern  CUresult (*libcuMemcpyAtoD_v2)(CUdeviceptr dstDevice, CUarray srcArray, size_t srcOffset, size_t ByteCount);
  extern  CUresult (*libcuMemcpyAtoH_v2)(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount);
  extern  CUresult (*libcuMemcpyDtoA_v2)(CUarray dstArray, size_t dstOffset, CUdeviceptr srcDevice, size_t ByteCount);
  extern  CUresult (*libcuMemcpyDtoD_v2)(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount);
  extern  CUresult (*libcuMemcpyDtoH_v2)(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount);
  extern  CUresult (*libcuMemcpyHtoA_v2)(CUarray dstArray, size_t dstOffset, const void* srcHost, size_t ByteCount);
  extern  CUresult (*libcuMemcpyHtoD_v2)(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount);
  extern  CUresult (*libcuMemFree_v2)(CUdeviceptr dptr);
  extern  CUresult (*libcuMemAlloc_v2)(CUdeviceptr *dptr, size_t bytesize);
  extern  CUresult (*libcuMemcpy) (CUdeviceptr dst, CUdeviceptr src, size_t ByteCount);
  extern  CUresult (*libcuLaunchKernel)(CUfunction  	f,
					unsigned int  	gridDimX,
					unsigned int  	gridDimY,
					unsigned int  	gridDimZ,
					unsigned int  	blockDimX,
					unsigned int  	blockDimY,
					unsigned int  	blockDimZ,
					unsigned int  	sharedMemBytes,
					CUstream  	hStream,
					void **  	kernelParams,
					void **  	extra);
#endif

  /* Kernel management */
  extern CUresult  (*libcuLaunchKernel)(CUfunction f,
                                unsigned int gridDimX,
                                unsigned int gridDimY,
                                unsigned int gridDimZ,
                                unsigned int blockDimX,
                                unsigned int blockDimY,
                                unsigned int blockDimZ,
                                unsigned int sharedMemBytes,
                                CUstream hStream,
                                void **kernelParams,
                                void **extra);
  extern CUresult  (*libcuLaunch)(CUfunction f);
  extern CUresult  (*libcuLaunchGrid)(CUfunction f, int grid_width, int grid_height);
  extern CUresult  (*libcuLaunchGridAsync)(CUfunction f, int grid_width, int grid_height, CUstream hStream);

  /* Memory Management */
  extern CUresult  (*libcuMemGetInfo_v2)(size_t *free, size_t *total);
  extern CUresult  (*libcuMemAlloc_v2)(CUdeviceptr *dptr, size_t bytesize);
  extern CUresult  (*libcuMemAllocPitch_v2)(CUdeviceptr *dptr, size_t *pPitch, size_t WidthInBytes, size_t Height, unsigned int ElementSizeBytes);
  extern CUresult  (*libcuMemFree_v2)(CUdeviceptr dptr);
  extern CUresult  (*libcuMemAllocHost_v2)(void **pp, size_t bytesize);
  extern CUresult  (*libcuMemFreeHost)(void *p);
  extern CUresult  (*libcuMemHostAlloc)(void **pp, size_t bytesize, unsigned int Flags);
  extern CUresult  (*libcuMemHostRegister)(void *p, size_t bytesize, unsigned int Flags);
  extern CUresult  (*libcuMemHostUnregister)(void *p);

  /* Memory Transfers */
  extern CUresult  (*libcuMemcpy)(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount);
  extern CUresult  (*libcuMemcpyPeer)(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount);
  extern CUresult  (*libcuMemcpyHtoD_v2)(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount);
  extern CUresult  (*libcuMemcpyDtoH_v2)(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount);
  extern CUresult  (*libcuMemcpyDtoD_v2)(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount);
  extern CUresult  (*libcuMemcpyDtoA_v2)(CUarray dstArray, size_t dstOffset, CUdeviceptr srcDevice, size_t ByteCount);
  extern CUresult  (*libcuMemcpyAtoD_v2)(CUdeviceptr dstDevice, CUarray srcArray, size_t srcOffset, size_t ByteCount);
  extern CUresult  (*libcuMemcpyHtoA_v2)(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount);
  extern CUresult  (*libcuMemcpyAtoH_v2)(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount);
  extern CUresult  (*libcuMemcpyAtoA_v2)(CUarray dstArray, size_t dstOffset, CUarray srcArray, size_t srcOffset, size_t ByteCount);
  extern CUresult  (*libcuMemcpy2D_v2)(const CUDA_MEMCPY2D *pCopy);
  extern CUresult  (*libcuMemcpy2DUnaligned_v2)(const CUDA_MEMCPY2D *pCopy);
  extern CUresult  (*libcuMemcpy3D_v2)(const CUDA_MEMCPY3D *pCopy);
  extern CUresult  (*libcuMemcpy3DPeer)(const CUDA_MEMCPY3D_PEER *pCopy);
  extern CUresult  (*libcuMemcpyAsync)(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount, CUstream hStream);
  extern CUresult  (*libcuMemcpyPeerAsync)(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount, CUstream hStream);
  extern CUresult  (*libcuMemcpyHtoDAsync_v2)(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount, CUstream hStream);
  extern CUresult  (*libcuMemcpyDtoHAsync_v2)(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream);
  extern CUresult  (*libcuMemcpyDtoDAsync_v2)(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream);
  extern CUresult  (*libcuMemcpyHtoAAsync_v2)(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount, CUstream hStream);
  extern CUresult  (*libcuMemcpyAtoHAsync_v2)(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount, CUstream hStream);
  extern CUresult  (*libcuMemcpy2DAsync_v2)(const CUDA_MEMCPY2D *pCopy, CUstream hStream);
  extern CUresult  (*libcuMemcpy3DAsync_v2)(const CUDA_MEMCPY3D *pCopy, CUstream hStream);
  extern CUresult  (*libcuMemcpy3DPeerAsync)(const CUDA_MEMCPY3D_PEER *pCopy, CUstream hStream);



  extern CUresult  (*libcuMemsetD8_v2)(CUdeviceptr dstDevice, unsigned char uc, size_t N);
  extern CUresult  (*libcuMemsetD16_v2)(CUdeviceptr dstDevice, unsigned short us, size_t N);
  extern CUresult  (*libcuMemsetD32_v2)(CUdeviceptr dstDevice, unsigned int ui, size_t N);
  extern CUresult  (*libcuMemsetD2D8_v2)(CUdeviceptr dstDevice, size_t dstPitch, unsigned char uc, size_t Width, size_t Height);
  extern CUresult  (*libcuMemsetD2D16_v2)(CUdeviceptr dstDevice, size_t dstPitch, unsigned short us, size_t Width, size_t Height);
  extern CUresult  (*libcuMemsetD2D32_v2)(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height);
  extern CUresult  (*libcuMemsetD8Async)(CUdeviceptr dstDevice, unsigned char uc, size_t N, CUstream hStream);
  extern CUresult  (*libcuMemsetD16Async)(CUdeviceptr dstDevice, unsigned short us, size_t N, CUstream hStream);
  extern CUresult  (*libcuMemsetD32Async)(CUdeviceptr dstDevice, unsigned int ui, size_t N, CUstream hStream);
  extern CUresult  (*libcuMemsetD2D8Async)(CUdeviceptr dstDevice, size_t dstPitch, unsigned char uc, size_t Width, size_t Height, CUstream hStream);
  extern CUresult  (*libcuMemsetD2D16Async)(CUdeviceptr dstDevice, size_t dstPitch, unsigned short us, size_t Width, size_t Height, CUstream hStream);
  extern CUresult  (*libcuMemsetD2D32Async)(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height, CUstream hStream);

#if 0
  /* is it useful ? */
  extern CUresult  (*libcuArrayCreate)(CUarray *pHandle, const CUDA_ARRAY_DESCRIPTOR *pAllocateArray);
  extern CUresult  (*libcuArrayGetDescriptor)(CUDA_ARRAY_DESCRIPTOR *pArrayDescriptor, CUarray hArray);
  extern CUresult  (*libcuArrayDestroy)(CUarray hArray);
  extern CUresult  (*libcuArray3DCreate)(CUarray *pHandle, const CUDA_ARRAY3D_DESCRIPTOR *pAllocateArray);
  extern CUresult  (*libcuArray3DGetDescriptor)(CUDA_ARRAY3D_DESCRIPTOR *pArrayDescriptor, CUarray hArray);
  extern CUresult  (*libcuMipmappedArrayCreate)(CUmipmappedArray *pHandle, const CUDA_ARRAY3D_DESCRIPTOR *pMipmappedArrayDesc, unsigned int numMipmapLevels);
  extern CUresult  (*libcuMipmappedArrayGetLevel)(CUarray *pLevelArray, CUmipmappedArray hMipmappedArray, unsigned int level);
  extern CUresult  (*libcuMipmappedArrayDestroy)(CUmipmappedArray hMipmappedArray);
#endif

  //extern CUresult  (*libcuCtxSynchronize)(void);
  //extern CUresult  (*libcuDeviceTotalMem)(unsigned int *bytes, CUdevice dev);
}
#endif	/* EZT_CUDA_H */
