/*
 * Copyright 1993-2010 NVIDIA Corporation.  All rights reserved.
 *
 * Please refer to the NVIDIA end user license agreement (EULA) associated
 * with this source code for terms and conditions that govern your use of
 * this software. Any use, reproduction, disclosure, or distribution of
 * this software and related documentation outside the terms of the EULA
 * is strictly prohibited.
 *
 */
 
 /*
* Copyright 1993-2010 NVIDIA Corporation.  All rights reserved.
*
* Please refer to the NVIDIA end user license agreement (EULA) associated
* with this source code for terms and conditions that govern your use of
* this software. Any use, reproduction, disclosure, or distribution of
* this software and related documentation outside the terms of the EULA
* is strictly prohibited.
*
*/


/* CUda UTility Library */

#pragma once

#ifdef _WIN32
#   pragma warning( disable : 4996 ) // disable deprecated warning 
#endif

#include <stdio.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

    // helper typedefs for building DLL
#ifdef _WIN32
#  ifdef BUILD_DLL
#    define DLL_MAPPING  __declspec(dllexport)
#  else
#    define DLL_MAPPING  __declspec(dllimport)
#  endif
#else 
#  define DLL_MAPPING 
#endif

#ifdef _WIN32
    #define CUTIL_API __stdcall
#else
    #define CUTIL_API
#endif

    ////////////////////////////////////////////////////////////////////////////
    //! CUT bool type
    ////////////////////////////////////////////////////////////////////////////
    enum CUTBoolean 
    {
        CUTFalse = 0,
        CUTTrue = 1
    };

    ////////////////////////////////////////////////////////////////////////////
    //! Deallocate memory allocated within Cutil
    //! @param  pointer to memory 
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    void CUTIL_API
  	cutFree( void* ptr);

    ////////////////////////////////////////////////////////////////////////////
    //! Helper for bank conflict checking (should only be used with the
    //! CUT_BANK_CHECKER macro)
    //! @param tidx  thread id in x dimension of block
    //! @param tidy  thread id in y dimension of block
    //! @param tidz  thread id in z dimension of block
    //! @param bdimx block size in x dimension
    //! @param bdimy block size in y dimension
    //! @param bdimz block size in z dimension
    //! @param file  name of the source file where the access takes place
    //! @param line  line in the source file where the access takes place
    //! @param aname name of the array which is accessed
    //! @param index index into the array
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    void CUTIL_API
    cutCheckBankAccess( unsigned int tidx, unsigned int tidy, unsigned int tidz,
                        unsigned int bdimx, unsigned int bdimy, 
                        unsigned int bdimz, const char* file, const int line,
                        const char* aname, const int index);

    ////////////////////////////////////////////////////////////////////////////
    //! Find the path for a filename
    //! @return the path if succeeded, otherwise 0
    //! @param filename        name of the file
    //! @param executablePath  optional absolute path of the executable
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    char* CUTIL_API
    cutFindFilePath(const char* filename, const char* executablePath);

    ////////////////////////////////////////////////////////////////////////////
    //! Read file \filename containing single precision floating point data
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param filename name of the source file
    //! @param data  uninitialized pointer, returned initialized and pointing to
    //!        the data read
    //! @param len  number of data elements in data, -1 on error
    //! @note If a NULL pointer is passed to this function and it is
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutReadFilef( const char* filename, float** data, unsigned int* len, 
                  bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Read file \filename containing double precision floating point data
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param filename name of the source file
    //! @param data  uninitialized pointer, returned initialized and pointing to
    //!        the data read
    //! @param len  number of data elements in data, -1 on error
    //! @note If a NULL pointer is passed to this function and it is
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutReadFiled( const char* filename, double** data, unsigned int* len, 
                  bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Read file \filename containing integer data
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param filename name of the source file
    //! @param data  uninitialized pointer, returned initialized and pointing to
    //!        the data read
    //! @param len  number of data elements in data, -1 on error
    //! @note If a NULL pointer is passed to this function and it is
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutReadFilei( const char* filename, int** data, unsigned int* len, bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Read file \filename containing unsigned integer data
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param filename name of the source file
    //! @param data  uninitialized pointer, returned initialized and pointing to
    //!        the data read
    //! @param len  number of data elements in data, -1 on error
    //! @note If a NULL pointer is passed to this function and it is 
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutReadFileui( const char* filename, unsigned int** data, 
                   unsigned int* len, bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Read file \filename containing char / byte data
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param filename name of the source file
    //! @param data  uninitialized pointer, returned initialized and pointing to
    //!        the data read
    //! @param len  number of data elements in data, -1 on error
    //! @note If a NULL pointer is passed to this function and it is 
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutReadFileb( const char* filename, char** data, unsigned int* len, 
                  bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Read file \filename containing unsigned char / byte data
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param filename name of the source file
    //! @param data  uninitialized pointer, returned initialized and pointing to
    //!        the data read
    //! @param len  number of data elements in data, -1 on error
    //! @note If a NULL pointer is passed to this function and it is
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutReadFileub( const char* filename, unsigned char** data, 
                   unsigned int* len, bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Write a data file \filename containing single precision floating point 
    //! data
    //! @return CUTTrue if writing the file succeeded, otherwise false
    //! @param filename name of the file to write
    //! @param data  pointer to data to write
    //! @param len  number of data elements in data, -1 on error
    //! @param epsilon  epsilon for comparison
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutWriteFilef( const char* filename, const float* data, unsigned int len,
                   const float epsilon, bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Write a data file \filename containing double precision floating point 
    //! data
    //! @return CUTTrue if writing the file succeeded, otherwise false
    //! @param filename name of the file to write
    //! @param data  pointer to data to write
    //! @param len  number of data elements in data, -1 on error
    //! @param epsilon  epsilon for comparison
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutWriteFiled( const char* filename, const float* data, unsigned int len,
                   const double epsilon, bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Write a data file \filename containing integer data
    //! @return CUTTrue if writing the file succeeded, otherwise false
    //! @param filename name of the file to write
    //! @param data  pointer to data to write
    //! @param len  number of data elements in data, -1 on error
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutWriteFilei( const char* filename, const int* data, unsigned int len,
                   bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Write a data file \filename containing unsigned integer data
    //! @return CUTTrue if writing the file succeeded, otherwise false
    //! @param filename name of the file to write
    //! @param data  pointer to data to write
    //! @param len  number of data elements in data, -1 on error
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutWriteFileui( const char* filename,const unsigned int* data, 
                    unsigned int len, bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Write a data file \filename containing char / byte data
    //! @return CUTTrue if writing the file succeeded, otherwise false
    //! @param filename name of the file to write
    //! @param data  pointer to data to write
    //! @param len  number of data elements in data, -1 on error
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutWriteFileb( const char* filename, const char* data, unsigned int len, 
                   bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Write a data file \filename containing unsigned char / byte data
    //! @return CUTTrue if writing the file succeeded, otherwise false
    //! @param filename name of the file to write
    //! @param data  pointer to data to write
    //! @param len  number of data elements in data, -1 on error
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutWriteFileub( const char* filename,const unsigned char* data,
                    unsigned int len, bool verbose = false);

    ////////////////////////////////////////////////////////////////////////////
    //! Load PGM image file (with unsigned char as data element type)
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    //! @note If a NULL pointer is passed to this function and it is 
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutLoadPGMub( const char* file, unsigned char** data,
                  unsigned int *w,unsigned int *h);

    ////////////////////////////////////////////////////////////////////////////
    //! Load PPM image file (with unsigned char as data element type)
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutLoadPPMub( const char* file, unsigned char** data, 
                  unsigned int *w,unsigned int *h);

    ////////////////////////////////////////////////////////////////////////////
    //! Load PPM image file (with unsigned char as data element type), padding 
    //! 4th component
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutLoadPPM4ub( const char* file, unsigned char** data, 
                   unsigned int *w,unsigned int *h);

    ////////////////////////////////////////////////////////////////////////////
    //! Load PGM image file (with unsigned int as data element type)
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    //! @note If a NULL pointer is passed to this function and it is 
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
        cutLoadPGMi( const char* file, unsigned int** data, 
                     unsigned int* w, unsigned int* h);

    ////////////////////////////////////////////////////////////////////////////
    //! Load PGM image file (with unsigned short as data element type)
    //! @return CUTTrue if reading the file succeeded, otherwise false
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    //! @note If a NULL pointer is passed to this function and it is 
    //!       initialized within Cutil then cutFree() has to be used to
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
        cutLoadPGMs( const char* file, unsigned short** data, 
                     unsigned int* w, unsigned int* h);

    ////////////////////////////////////////////////////////////////////////////
    //! Load PGM image file (with float as data element type)
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    //! @note If a NULL pointer is passed to this function and it is 
    //!       initialized within Cutil then cutFree() has to be used to 
    //!       deallocate the memory
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
        cutLoadPGMf( const char* file, float** data,
                     unsigned int* w, unsigned int* h);

    ////////////////////////////////////////////////////////////////////////////
    //! Save PGM image file (with unsigned char as data element type)
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
        cutSavePGMub( const char* file, unsigned char* data, 
                      unsigned int w, unsigned int h);

    ////////////////////////////////////////////////////////////////////////////
    //! Save PPM image file (with unsigned char as data element type)
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutSavePPMub( const char* file, unsigned char *data, 
                unsigned int w, unsigned int h);

    ////////////////////////////////////////////////////////////////////////////
    //! Save PPM image file (with unsigned char as data element type, padded to 
    //! 4 bytes)
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutSavePPM4ub( const char* file, unsigned char *data, 
                   unsigned int w, unsigned int h);

    ////////////////////////////////////////////////////////////////////////////
    //! Save PGM image file (with unsigned int as data element type)
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutSavePGMi( const char* file, unsigned int* data,
                 unsigned int w, unsigned int h);

    ////////////////////////////////////////////////////////////////////////////
    //! Save PGM image file (with unsigned short as data element type)
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutSavePGMs( const char* file, unsigned short* data,
                 unsigned int w, unsigned int h);

    ////////////////////////////////////////////////////////////////////////////
    //! Save PGM image file (with float as data element type)
    //! @param file  name of the image file
    //! @param data  handle to the data read
    //! @param w     width of the image
    //! @param h     height of the image
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutSavePGMf( const char* file, float* data,
                 unsigned int w, unsigned int h);

    ////////////////////////////////////////////////////////////////////////////
    // Command line arguments: General notes
    // * All command line arguments begin with '--' followed by the token; 
    //   token and value are separated by '='; example --samples=50
    // * Arrays have the form --model=[one.obj,two.obj,three.obj] 
    //   (without whitespaces)
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    //! Check if command line argument \a flag-name is given
    //! @return CUTTrue if command line argument \a flag_name has been given, 
    //!         otherwise 0
    //! @param argc  argc as passed to main()
    //! @param argv  argv as passed to main()
    //! @param flag_name  name of command line flag
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutCheckCmdLineFlag( const int argc, const char** argv, 
                         const char* flag_name);

    ////////////////////////////////////////////////////////////////////////////
    //! Get the value of a command line argument of type int
    //! @return CUTTrue if command line argument \a arg_name has been given and
    //!         is of the requested type, otherwise CUTFalse
    //! @param argc  argc as passed to main()
    //! @param argv  argv as passed to main()
    //! @param arg_name  name of the command line argument
    //! @param val  value of the command line argument
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutGetCmdLineArgumenti( const int argc, const char** argv, 
                            const char* arg_name, int* val);

    ////////////////////////////////////////////////////////////////////////////
    //! Get the value of a command line argument of type float
    //! @return CUTTrue if command line argument \a arg_name has been given and
    //!         is of the requested type, otherwise CUTFalse
    //! @param argc  argc as passed to main()
    //! @param argv  argv as passed to main()
    //! @param arg_name  name of the command line argument
    //! @param val  value of the command line argument
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutGetCmdLineArgumentf( const int argc, const char** argv, 
                            const char* arg_name, float* val);

    ////////////////////////////////////////////////////////////////////////////
    //! Get the value of a command line argument of type string
    //! @return CUTTrue if command line argument \a arg_name has been given and
    //!         is of the requested type, otherwise CUTFalse
    //! @param argc  argc as passed to main()
    //! @param argv  argv as passed to main()
    //! @param arg_name  name of the command line argument
    //! @param val  value of the command line argument
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutGetCmdLineArgumentstr( const int argc, const char** argv, 
                              const char* arg_name, char** val);

    ////////////////////////////////////////////////////////////////////////////
    //! Get the value of a command line argument list those element are strings
    //! @return CUTTrue if command line argument \a arg_name has been given and
    //!         is of the requested type, otherwise CUTFalse
    //! @param argc  argc as passed to main()
    //! @param argv  argv as passed to main()
    //! @param arg_name  name of the command line argument
    //! @param val  command line argument list
    //! @param len  length of the list / number of elements
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutGetCmdLineArgumentListstr( const int argc, const char** argv, 
                                  const char* arg_name, char** val, 
                                  unsigned int* len);

    ////////////////////////////////////////////////////////////////////////////
    //! Extended assert
    //! @return CUTTrue if the condition \a val holds, otherwise CUTFalse
    //! @param val  condition to test
    //! @param file  __FILE__ macro
    //! @param line  __LINE__ macro
    //! @note This function should be used via the CONDITION(val) macro
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutCheckCondition( int val, const char* file, const int line);

    ////////////////////////////////////////////////////////////////////////////
    //! Compare two float arrays
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutComparef( const float* reference, const float* data,
                 const unsigned int len);

    ////////////////////////////////////////////////////////////////////////////
    //! Compare two integer arrays
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutComparei( const int* reference, const int* data, 
                 const unsigned int len ); 

    ////////////////////////////////////////////////////////////////////////////////
    //! Compare two unsigned integer arrays, with epsilon and threshold
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    //! @param threshold  tolerance % # of comparison errors (0.15f = 15%)
    ////////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutCompareuit( const unsigned int* reference, const unsigned int* data,
                const unsigned int len, const float epsilon, const float threshold );

    ////////////////////////////////////////////////////////////////////////////
    //! Compare two unsigned char arrays
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutCompareub( const unsigned char* reference, const unsigned char* data,
                  const unsigned int len ); 

    ////////////////////////////////////////////////////////////////////////////////
    //! Compare two integers with a tolernance for # of byte errors
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    //! @param epsilon    epsilon to use for the comparison
    //! @param threshold  tolerance % # of comparison errors (0.15f = 15%)
    ////////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutCompareubt( const unsigned char* reference, const unsigned char* data,
                 const unsigned int len, const float epsilon, const float threshold );

    ////////////////////////////////////////////////////////////////////////////////
    //! Compare two integer arrays with an epsilon tolerance for equality
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    //! @param epsilon    epsilon to use for the comparison
    ////////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutCompareube( const unsigned char* reference, const unsigned char* data,
                 const unsigned int len, const float epsilon );

    ////////////////////////////////////////////////////////////////////////////
    //! Compare two float arrays with an epsilon tolerance for equality
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    //! @param epsilon    epsilon to use for the comparison
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutComparefe( const float* reference, const float* data,
                  const unsigned int len, const float epsilon );

    ////////////////////////////////////////////////////////////////////////////////
    //! Compare two float arrays with an epsilon tolerance for equality and a 
    //!     threshold for # pixel errors
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    //! @param epsilon    epsilon to use for the comparison
    ////////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
    cutComparefet( const float* reference, const float* data,
                 const unsigned int len, const float epsilon, const float threshold );

    ////////////////////////////////////////////////////////////////////////////
    //! Compare two float arrays using L2-norm with an epsilon tolerance for 
    //! equality
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param reference  handle to the reference data / gold image
    //! @param data       handle to the computed data
    //! @param len        number of elements in reference and data
    //! @param epsilon    epsilon to use for the comparison
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutCompareL2fe( const float* reference, const float* data,
                    const unsigned int len, const float epsilon );

	////////////////////////////////////////////////////////////////////////////////
    //! Compare two PPM image files with an epsilon tolerance for equality
    //! @return  CUTTrue if \a reference and \a data are identical, 
    //!          otherwise CUTFalse
    //! @param src_file   filename for the image to be compared
    //! @param data       filename for the reference data / gold image
    //! @param epsilon    epsilon to use for the comparison
    //! @param threshold  threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass)
    //! $param verboseErrors output details of image mismatch to std::err
    ////////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API
	cutComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold, bool verboseErrors = false );


    ////////////////////////////////////////////////////////////////////////////
    //! Timer functionality

    ////////////////////////////////////////////////////////////////////////////
    //! Create a new timer
    //! @return CUTTrue if a time has been created, otherwise false
    //! @param  name of the new timer, 0 if the creation failed
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutCreateTimer( unsigned int* name);

    ////////////////////////////////////////////////////////////////////////////
    //! Delete a timer
    //! @return CUTTrue if a time has been deleted, otherwise false
    //! @param  name of the timer to delete
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutDeleteTimer( unsigned int name);

    ////////////////////////////////////////////////////////////////////////////
    //! Start the time with name \a name
    //! @param name  name of the timer to start
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutStartTimer( const unsigned int name);

    ////////////////////////////////////////////////////////////////////////////
    //! Stop the time with name \a name. Does not reset.
    //! @param name  name of the timer to stop
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutStopTimer( const unsigned int name);

    ////////////////////////////////////////////////////////////////////////////
    //! Resets the timer's counter.
    //! @param name  name of the timer to reset.
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    CUTBoolean CUTIL_API 
    cutResetTimer( const unsigned int name);

    ////////////////////////////////////////////////////////////////////////////
    //! Returns total execution time in milliseconds for the timer over all 
    //! runs since the last reset or timer creation.
    //! @param name  name of the timer to return the time of
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    float CUTIL_API 
    cutGetTimerValue( const unsigned int name);

    ////////////////////////////////////////////////////////////////////////////
    //! Return the average time in milliseconds for timer execution as the 
    //! total  time for the timer dividied by the number of completed (stopped)
    //! runs the timer has made.
    //! Excludes the current running time if the timer is currently running.
    //! @param name  name of the timer to return the time of
    ////////////////////////////////////////////////////////////////////////////
    DLL_MAPPING
    float CUTIL_API 
    cutGetAverageTimerValue( const unsigned int name);

    ////////////////////////////////////////////////////////////////////////////
    //! Macros

// This is for the CUTIL bank checker
#ifdef _DEBUG
    #if __DEVICE_EMULATION__
        // Interface for bank conflict checker
    #define CUT_BANK_CHECKER( array, index)                                      \
        (cutCheckBankAccess( threadIdx.x, threadIdx.y, threadIdx.z, blockDim.x,  \
        blockDim.y, blockDim.z,                                                  \
        __FILE__, __LINE__, #array, index ),                                     \
        array[index])
    #else
    #define CUT_BANK_CHECKER( array, index)  array[index]
    #endif
#else
    #define CUT_BANK_CHECKER( array, index)  array[index]
#endif

#  define CU_SAFE_CALL_NO_SYNC( call ) {                                     \
    CUresult err = call;                                                     \
    if( CUDA_SUCCESS != err) {                                               \
        fprintf(stderr, "Cuda driver error %x in file '%s' in line %i.\n",   \
                err, __FILE__, __LINE__ );                                   \
        exit(EXIT_FAILURE);                                                  \
    } }

#  define CU_SAFE_CALL( call )       CU_SAFE_CALL_NO_SYNC(call);

#  define CU_SAFE_CTX_SYNC( ) {                                              \
    CUresult err = cuCtxSynchronize();                                       \
    if( CUDA_SUCCESS != err) {                                               \
        fprintf(stderr, "Cuda driver error %x in file '%s' in line %i.\n",   \
                err, __FILE__, __LINE__ );                                   \
        exit(EXIT_FAILURE);                                                  \
    } }

#  define CUDA_SAFE_CALL_NO_SYNC( call) {                                    \
    cudaError err = call;                                                    \
    if( cudaSuccess != err) {                                                \
        fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n",        \
                __FILE__, __LINE__, cudaGetErrorString( err) );              \
        exit(EXIT_FAILURE);                                                  \
    } }

#  define CUDA_SAFE_CALL( call)     CUDA_SAFE_CALL_NO_SYNC(call);                                            \

#  define CUDA_SAFE_THREAD_SYNC( ) {                                         \
    cudaError err = cudaDeviceSynchronize();                                 \
    if ( cudaSuccess != err) {                                               \
        fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n",        \
                __FILE__, __LINE__, cudaGetErrorString( err) );              \
    } }

#  define CUFFT_SAFE_CALL( call) {                                           \
    cufftResult err = call;                                                  \
    if( CUFFT_SUCCESS != err) {                                              \
        fprintf(stderr, "CUFFT error in file '%s' in line %i.\n",            \
                __FILE__, __LINE__);                                         \
        exit(EXIT_FAILURE);                                                  \
    } }

#  define CUT_SAFE_CALL( call)                                               \
    if( CUTTrue != call) {                                                   \
        fprintf(stderr, "Cut error in file '%s' in line %i.\n",              \
                __FILE__, __LINE__);                                         \
        exit(EXIT_FAILURE);                                                  \
    } 

    //! Check for CUDA error
#ifdef _DEBUG
#  define CUT_CHECK_ERROR(errorMessage) {                                    \
    cudaError_t err = cudaGetLastError();                                    \
    if( cudaSuccess != err) {                                                \
        fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n",    \
                errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    err = cudaDeviceSynchronize();                                           \
    if( cudaSuccess != err) {                                                \
        fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n",    \
                errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    }
#else
#  define CUT_CHECK_ERROR(errorMessage) {                                    \
    cudaError_t err = cudaGetLastError();                                    \
    if( cudaSuccess != err) {                                                \
        fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n",    \
                errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    }
#endif

    //! Check for malloc error
#  define CUT_SAFE_MALLOC( mallocCall ) {                                    \
    if( !(mallocCall)) {                                                     \
        fprintf(stderr, "Host malloc failure in file '%s' in line %i\n",     \
                __FILE__, __LINE__);                                         \
        exit(EXIT_FAILURE);                                                  \
    } } while(0);

    //! Check if condition is true (flexible assert)
#  define CUT_CONDITION( val)                                                \
    if( CUTFalse == cutCheckCondition( val, __FILE__, __LINE__)) {           \
        exit(EXIT_FAILURE);                                                  \
    }

#if __DEVICE_EMULATION__

#  define CUT_DEVICE_INIT(ARGC, ARGV)

#else

#  define CUT_DEVICE_INIT(ARGC, ARGV) {                                      \
    int deviceCount;                                                         \
    CUDA_SAFE_CALL_NO_SYNC(cudaGetDeviceCount(&deviceCount));                \
    if (deviceCount == 0) {                                                  \
        fprintf(stderr, "cutil error: no devices supporting CUDA.\n");       \
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    int dev = 0;                                                             \
    cutGetCmdLineArgumenti(ARGC, (const char **) ARGV, "device", &dev);      \
	if (dev < 0) dev = 0;                                                    \
    if (dev > deviceCount-1) dev = deviceCount - 1;                          \
    cudaDeviceProp deviceProp;                                               \
    CUDA_SAFE_CALL_NO_SYNC(cudaGetDeviceProperties(&deviceProp, dev));       \
    if (deviceProp.major < 1) {                                              \
        fprintf(stderr, "cutil error: device does not support CUDA.\n");     \
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    if (cutCheckCmdLineFlag(ARGC, (const char **) ARGV, "quiet") == CUTFalse) \
        fprintf(stderr, "Using device %d: %s\n", dev, deviceProp.name);       \
    CUDA_SAFE_CALL(cudaSetDevice(dev));                                      \
}


    //! Check for CUDA context lost
#  define CUDA_CHECK_CTX_LOST(errorMessage) {                                \
    cudaError_t err = cudaGetLastError();                                    \
    if( cudaSuccess != err) {                                                \
        fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n",    \
                errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    err = cudaDeviceSynchronize();                                           \
    if( cudaSuccess != err) {                                                \
        fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n",    \
                errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
        exit(EXIT_FAILURE);                                                  \
    } }

//! Check for CUDA context lost
#  define CU_CHECK_CTX_LOST(errorMessage) {                                  \
    cudaError_t err = cudaGetLastError();                                    \
    if( CUDA_ERROR_INVALID_CONTEXT != err) {                                 \
        fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n",    \
                errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    err = cudaDeviceSynchronize();                                           \
    if( cudaSuccess != err) {                                                \
        fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n",    \
                errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
        exit(EXIT_FAILURE);                                                  \
    } }


#endif

#  define CUT_DEVICE_INIT_DRV(cuDevice, ARGC, ARGV) {                        \
    cuDevice = 0;                                                            \
    int deviceCount = 0;                                                     \
    CUresult err = cuInit(0);                                                \
    if (CUDA_SUCCESS == err)                                                 \
        CU_SAFE_CALL_NO_SYNC(cuDeviceGetCount(&deviceCount));                \
    if (deviceCount == 0) {                                                  \
        fprintf(stderr, "cutil error: no devices supporting CUDA\n");        \
        exit(EXIT_FAILURE);                                                  \
    }                                                                        \
    int dev = 0;                                                             \
    cutGetCmdLineArgumenti(ARGC, (const char **) ARGV, "device", &dev);      \
	if (dev < 0) dev = 0;                                                    \
    if (dev > deviceCount-1) dev = deviceCount - 1;                          \
    CU_SAFE_CALL_NO_SYNC(cuDeviceGet(&cuDevice, dev));                       \
    char name[100];                                                          \
    cuDeviceGetName(name, 100, cuDevice);                                    \
    if (cutCheckCmdLineFlag(ARGC, (const char **) ARGV, "quiet") == CUTFalse) \
        fprintf(stderr, "Using device %d: %s\n", dev, name);                  \
}

#define CUT_EXIT(argc, argv)                                                 \
    if (!cutCheckCmdLineFlag(argc, (const char**)argv, "noprompt")) {        \
        printf("\nPress ENTER to exit...\n");                                \
        fflush( stdout);                                                     \
        fflush( stderr);                                                     \
        getchar();                                                           \
    }                                                                        \
    exit(EXIT_SUCCESS);


#ifdef __cplusplus
}
#endif  // #ifdef _DEBUG (else branch)
