vortex/tests/opencl/blackscholes/shrUtils.cpp
Blaise Tine d47cccc157 Vortex 2.0 changes:
+ Microarchitecture optimizations
+ 64-bit support
+ Xilinx FPGA support
+ LLVM-16 support
+ Refactoring and quality control fixes
2023-10-19 20:51:22 -07:00

1954 lines
No EOL
73 KiB
C++

/*
* 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.
*
*/
// *********************************************************************
// Generic Utilities for NVIDIA GPU Computing SDK
// *********************************************************************
// includes
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "shrUtils.h"
#include "cmd_arg_reader.h"
// size of PGM file header
const unsigned int PGMHeaderSize = 0x40;
#define MIN_EPSILON_ERROR 1e-3f
// Deallocate memory allocated within shrUtils
// *********************************************************************
void shrFree(void* ptr)
{
if( NULL != ptr) free( ptr);
}
// Helper function to init data arrays
// *********************************************************************
void shrFillArray(float* pfData, int iSize)
{
int i;
const float fScale = 1.0f / (float)RAND_MAX;
for (i = 0; i < iSize; ++i)
{
pfData[i] = fScale * rand();
}
}
// Helper function to print data arrays
// *********************************************************************
void shrPrintArray(float* pfData, int iSize)
{
int i;
for (i = 0; i < iSize; ++i)
{
shrLog("%d: %.3f\n", i, pfData[i]);
}
}
// Helper function to return precision delta time for 3 counters since last call based upon host high performance counter
// *********************************************************************
double shrDeltaT(int iCounterID = 0)
{
// local var for computation of microseconds since last call
double DeltaT;
#ifdef _WIN32 // Windows version of precision host timer
// Variables that need to retain state between calls
static LARGE_INTEGER liOldCount0 = {0, 0};
static LARGE_INTEGER liOldCount1 = {0, 0};
static LARGE_INTEGER liOldCount2 = {0, 0};
// locals for new count, new freq and new time delta
LARGE_INTEGER liNewCount, liFreq;
if (QueryPerformanceFrequency(&liFreq))
{
// Get new counter reading
QueryPerformanceCounter(&liNewCount);
// Update the requested timer
switch (iCounterID)
{
case 0:
{
// Calculate time difference for timer 0. (zero when called the first time)
DeltaT = liOldCount0.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount0.QuadPart) / (double)liFreq.QuadPart) : 0.0;
// Reset old count to new
liOldCount0 = liNewCount;
break;
}
case 1:
{
// Calculate time difference for timer 1. (zero when called the first time)
DeltaT = liOldCount1.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount1.QuadPart) / (double)liFreq.QuadPart) : 0.0;
// Reset old count to new
liOldCount1 = liNewCount;
break;
}
case 2:
{
// Calculate time difference for timer 2. (zero when called the first time)
DeltaT = liOldCount2.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount2.QuadPart) / (double)liFreq.QuadPart) : 0.0;
// Reset old count to new
liOldCount2 = liNewCount;
break;
}
default:
{
// Requested counter ID out of range
return -9999.0;
}
}
// Returns time difference in seconds sunce the last call
return DeltaT;
}
else
{
// No high resolution performance counter
return -9999.0;
}
#else // Linux version of precision host timer. See http://www.informit.com/articles/article.aspx?p=23618&seqNum=8
static struct timeval _NewTime; // new wall clock time (struct representation in seconds and microseconds)
static struct timeval _OldTime0; // old wall clock time 0(struct representation in seconds and microseconds)
static struct timeval _OldTime1; // old wall clock time 1(struct representation in seconds and microseconds)
static struct timeval _OldTime2; // old wall clock time 2(struct representation in seconds and microseconds)
// Get new counter reading
gettimeofday(&_NewTime, NULL);
switch (iCounterID)
{
case 0:
{
// Calculate time difference for timer 0. (zero when called the first time)
DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime0.tv_sec + 1.0e-6 * (double)_OldTime0.tv_usec);
// Reset old time 0 to new
_OldTime0.tv_sec = _NewTime.tv_sec;
_OldTime0.tv_usec = _NewTime.tv_usec;
break;
}
case 1:
{
// Calculate time difference for timer 1. (zero when called the first time)
DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime1.tv_sec + 1.0e-6 * (double)_OldTime1.tv_usec);
// Reset old time 1 to new
_OldTime1.tv_sec = _NewTime.tv_sec;
_OldTime1.tv_usec = _NewTime.tv_usec;
break;
}
case 2:
{
// Calculate time difference for timer 2. (zero when called the first time)
DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime2.tv_sec + 1.0e-6 * (double)_OldTime2.tv_usec);
// Reset old time 2 to new
_OldTime2.tv_sec = _NewTime.tv_sec;
_OldTime2.tv_usec = _NewTime.tv_usec;
break;
}
default:
{
// Requested counter ID out of range
return -9999.0;
}
}
// Returns time difference in seconds sunce the last call
return DeltaT;
#endif
}
// Optional LogFileName Override function
// *********************************************************************
char* cLogFilePathAndName = NULL;
void shrSetLogFileName (const char* cOverRideName)
{
if( cLogFilePathAndName != NULL ) {
free(cLogFilePathAndName);
}
cLogFilePathAndName = (char*) malloc(strlen(cOverRideName) + 1);
#ifdef WIN32
strcpy_s(cLogFilePathAndName, strlen(cOverRideName) + 1, cOverRideName);
#else
strcpy(cLogFilePathAndName, cOverRideName);
#endif
return;
}
// Function to log standardized information to console, file or both
// *********************************************************************
static int shrLogV(int iLogMode, int iErrNum, const char* cFormatString, va_list vaArgList)
{
static FILE* pFileStream0 = NULL;
static FILE* pFileStream1 = NULL;
size_t szNumWritten = 0;
char cFileMode [3];
// if the sample log file is closed and the call incudes a "write-to-file", open file for writing
if ((pFileStream0 == NULL) && (iLogMode & LOGFILE))
{
// if the default filename has not been overriden, set to default
if (cLogFilePathAndName == NULL)
{
shrSetLogFileName(DEFAULTLOGFILE);
}
#ifdef _WIN32 // Windows version
// set the file mode
if (iLogMode & APPENDMODE) // append to prexisting file contents
{
sprintf_s (cFileMode, 3, "a+");
}
else // replace prexisting file contents
{
sprintf_s (cFileMode, 3, "w");
}
// open the individual sample log file in the requested mode
errno_t err = fopen_s(&pFileStream0, cLogFilePathAndName, cFileMode);
// if error on attempt to open, be sure the file is null or close it, then return negative error code
if (err != 0)
{
if (pFileStream0)
{
fclose (pFileStream0);
}
return -err;
}
#else // Linux & Mac version
// set the file mode
if (iLogMode & APPENDMODE) // append to prexisting file contents
{
sprintf (cFileMode, "a+");
}
else // replace prexisting file contents
{
sprintf (cFileMode, "w");
}
// open the file in the requested mode
if ((pFileStream0 = fopen(cLogFilePathAndName, cFileMode)) == 0)
{
// if error on attempt to open, be sure the file is null or close it, then return negative error code
if (pFileStream0)
{
fclose (pFileStream0);
}
return -1;
}
#endif
}
// if the master log file is closed and the call incudes a "write-to-file" and MASTER, open master logfile file for writing
if ((pFileStream1 == NULL) && (iLogMode & LOGFILE) && (iLogMode & MASTER))
{
#ifdef _WIN32 // Windows version
// open the master log file in append mode
errno_t err = fopen_s(&pFileStream1, MASTERLOGFILE, "a+");
// if error on attempt to open, be sure the file is null or close it, then return negative error code
if (err != 0)
{
if (pFileStream1)
{
fclose (pFileStream1);
pFileStream1 = NULL;
}
iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid
// return -err;
}
#else // Linux & Mac version
// open the file in the requested mode
if ((pFileStream1 = fopen(MASTERLOGFILE, "a+")) == 0)
{
// if error on attempt to open, be sure the file is null or close it, then return negative error code
if (pFileStream1)
{
fclose (pFileStream1);
pFileStream1 = NULL;
}
iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid
// return -1;
}
#endif
// If master log file length has become excessive, empty/reopen
if (iLogMode != LOGCONSOLE)
{
fseek(pFileStream1, 0L, SEEK_END);
if (ftell(pFileStream1) > 50000L)
{
fclose (pFileStream1);
#ifdef _WIN32 // Windows version
fopen_s(&pFileStream1, MASTERLOGFILE, "w");
#else
pFileStream1 = fopen(MASTERLOGFILE, "w");
#endif
}
}
}
// Handle special Error Message code
if (iLogMode & ERRORMSG)
{
// print string to console if flagged
if (iLogMode & LOGCONSOLE)
{
szNumWritten = printf ("\n !!! Error # %i at ", iErrNum); // console
}
// print string to file if flagged
if (iLogMode & LOGFILE)
{
szNumWritten = fprintf (pFileStream0, "\n !!! Error # %i at ", iErrNum); // sample log file
}
}
// Vars used for variable argument processing
const char* pStr;
const char* cArg;
int iArg;
double dArg;
unsigned int uiArg;
std::string sFormatSpec;
const std::string sFormatChars = " -+#0123456789.dioufnpcsXxEeGgAa";
const std::string sTypeChars = "dioufnpcsXxEeGgAa";
char cType = 'c';
// Start at the head of the string and scan to the null at the end
for (pStr = cFormatString; *pStr; ++pStr)
{
// Check if the current character is not a formatting specifier ('%')
if (*pStr != '%')
{
// character is not '%', so print it verbatim to console and/or files as flagged
if (iLogMode & LOGCONSOLE)
{
szNumWritten = putc(*pStr, stdout); // console
}
if (iLogMode & LOGFILE)
{
szNumWritten = putc(*pStr, pFileStream0); // sample log file
if (iLogMode & MASTER)
{
szNumWritten = putc(*pStr, pFileStream1); // master log file
}
}
}
else
{
// character is '%', so skip over it and read the full format specifier for the argument
++pStr;
sFormatSpec = '%';
// special handling for string of %%%%
bool bRepeater = (*pStr == '%');
if (bRepeater)
{
cType = '%';
}
// chars after the '%' are part of format if on list of constants... scan until that isn't true or NULL is found
while (pStr && ((sFormatChars.find(*pStr) != std::string::npos) || bRepeater))
{
sFormatSpec += *pStr;
// If the char is a type specifier, trap it and stop scanning
// (a type specifier char is always the last in the format except for string of %%%)
if (sTypeChars.find(*pStr) != std::string::npos)
{
cType = *pStr;
break;
}
// Special handling for string of %%%
// If a string of %%% was started and then it ends, break (There won't be a typical type specifier)
if (bRepeater && (*pStr != '%'))
{
break;
}
pStr++;
}
// Now handle the arg according to type
switch (cType)
{
case '%': // special handling for string of %%%%
{
if (iLogMode & LOGCONSOLE)
{
szNumWritten = printf(sFormatSpec.c_str()); // console
}
if (iLogMode & LOGFILE)
{
szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str()); // sample log file
if (iLogMode & MASTER)
{
szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str()); // master log file
}
}
continue;
}
case 'c': // single byte char
case 's': // string of single byte chars
{
// Set cArg as the next value in list and print to console and/or files if flagged
cArg = va_arg(vaArgList, char*);
if (iLogMode & LOGCONSOLE)
{
szNumWritten = printf(sFormatSpec.c_str(), cArg); // console
}
if (iLogMode & LOGFILE)
{
szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), cArg); // sample log file
if (iLogMode & MASTER)
{
szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), cArg); // master log file
}
}
continue;
}
case 'd': // signed decimal integer
case 'i': // signed decimal integer
{
// set iArg as the next value in list and print to console and/or files if flagged
iArg = va_arg(vaArgList, int);
if (iLogMode & LOGCONSOLE)
{
szNumWritten = printf(sFormatSpec.c_str(), iArg); // console
}
if (iLogMode & LOGFILE)
{
szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), iArg); // sample log file
if (iLogMode & MASTER)
{
szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), iArg); // master log file
}
}
continue;
}
case 'u': // unsigned decimal integer
case 'o': // unsigned octal integer
case 'x': // unsigned hexadecimal integer using "abcdef"
case 'X': // unsigned hexadecimal integer using "ABCDEF"
{
// set uiArg as the next value in list and print to console and/or files if flagged
uiArg = va_arg(vaArgList, unsigned int);
if (iLogMode & LOGCONSOLE)
{
szNumWritten = printf(sFormatSpec.c_str(), uiArg); // console
}
if (iLogMode & LOGFILE)
{
szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), uiArg); // sample log file
if (iLogMode & MASTER)
{
szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), uiArg); // master log file
}
}
continue;
}
case 'f': // float/double
case 'e': // scientific double/float
case 'E': // scientific double/float
case 'g': // scientific double/float
case 'G': // scientific double/float
case 'a': // signed hexadecimal double precision float
case 'A': // signed hexadecimal double precision float
{
// set dArg as the next value in list and print to console and/or files if flagged
dArg = va_arg(vaArgList, double);
if (iLogMode & LOGCONSOLE)
{
szNumWritten = printf(sFormatSpec.c_str(), dArg); // console
}
if (iLogMode & LOGFILE)
{
szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), dArg); // sample log file
if (iLogMode & MASTER)
{
szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), dArg); // master log file
}
}
continue;
}
default:
{
// print arg of unknown/unsupported type to console and/or file if flagged
if (iLogMode & LOGCONSOLE) // console
{
szNumWritten = putc(*pStr, stdout);
}
if (iLogMode & LOGFILE)
{
szNumWritten = putc(*pStr, pFileStream0); // sample log file
if (iLogMode & MASTER)
{
szNumWritten = putc(*pStr, pFileStream1); // master log file
}
}
}
}
}
}
// end the sample log with a horizontal line if closing
if (iLogMode & CLOSELOG)
{
if (iLogMode & LOGCONSOLE)
{
printf(HDASHLINE);
}
if (iLogMode & LOGFILE)
{
fprintf(pFileStream0, HDASHLINE);
}
}
// flush console and/or file buffers if updated
if (iLogMode & LOGCONSOLE)
{
fflush(stdout);
}
if (iLogMode & LOGFILE)
{
fflush (pFileStream0);
// if the master log file has been updated, flush it too
if (iLogMode & MASTER)
{
fflush (pFileStream1);
}
}
// If the log file is open and the caller requests "close file", then close and NULL file handle
if ((pFileStream0) && (iLogMode & CLOSELOG))
{
fclose (pFileStream0);
pFileStream0 = NULL;
}
if ((pFileStream1) && (iLogMode & CLOSELOG))
{
fclose (pFileStream1);
pFileStream1 = NULL;
}
// return error code or OK
if (iLogMode & ERRORMSG)
{
return iErrNum;
}
else
{
return 0;
}
}
// Function to log standardized information to console, file or both
// *********************************************************************
int shrLogEx(int iLogMode = LOGCONSOLE, int iErrNum = 0, const char* cFormatString = "", ...)
{
va_list vaArgList;
// Prepare variable agument list
va_start(vaArgList, cFormatString);
int ret = shrLogV(iLogMode, iErrNum, cFormatString, vaArgList);
// end variable argument handler
va_end(vaArgList);
return ret;
}
// Function to log standardized information to console, file or both
// *********************************************************************
int shrLog(const char* cFormatString = "", ...)
{
va_list vaArgList;
// Prepare variable agument list
va_start(vaArgList, cFormatString);
int ret = shrLogV(LOGBOTH, 0, cFormatString, vaArgList);
// end variable argument handler
va_end(vaArgList);
return ret;
}
//////////////////////////////////////////////////////////////////////////////
//! Find the path for a file assuming that
//! files are found in the searchPath.
//!
//! @return the path if succeeded, otherwise 0
//! @param filename name of the file
//! @param executable_path optional absolute path of the executable
//////////////////////////////////////////////////////////////////////////////
char* shrFindFilePath(const char* filename, const char* executable_path)
{
// <executable_name> defines a variable that is replaced with the name of the executable
// Typical relative search paths to locate needed companion files (e.g. sample input data, or JIT source files)
// The origin for the relative search may be the .exe file, a .bat file launching an .exe, a browser .exe launching the .exe or .bat, etc
const char* searchPath[] =
{
"./", // same dir
"./data/", // "/data/" subdir
"./src/", // "/src/" subdir
"./src/<executable_name>/data/", // "/src/<executable_name>/data/" subdir
"./inc/", // "/inc/" subdir
"../", // up 1 in tree
"../data/", // up 1 in tree, "/data/" subdir
"../src/", // up 1 in tree, "/src/" subdir
"../inc/", // up 1 in tree, "/inc/" subdir
"../OpenCL/src/<executable_name>/", // up 1 in tree, "/OpenCL/src/<executable_name>/" subdir
"../OpenCL/src/<executable_name>/data/", // up 1 in tree, "/OpenCL/src/<executable_name>/data/" subdir
"../OpenCL/src/<executable_name>/src/", // up 1 in tree, "/OpenCL/src/<executable_name>/src/" subdir
"../OpenCL/src/<executable_name>/inc/", // up 1 in tree, "/OpenCL/src/<executable_name>/inc/" subdir
"../C/src/<executable_name>/", // up 1 in tree, "/C/src/<executable_name>/" subdir
"../C/src/<executable_name>/data/", // up 1 in tree, "/C/src/<executable_name>/data/" subdir
"../C/src/<executable_name>/src/", // up 1 in tree, "/C/src/<executable_name>/src/" subdir
"../C/src/<executable_name>/inc/", // up 1 in tree, "/C/src/<executable_name>/inc/" subdir
"../DirectCompute/src/<executable_name>/", // up 1 in tree, "/DirectCompute/src/<executable_name>/" subdir
"../DirectCompute/src/<executable_name>/data/", // up 1 in tree, "/DirectCompute/src/<executable_name>/data/" subdir
"../DirectCompute/src/<executable_name>/src/", // up 1 in tree, "/DirectCompute/src/<executable_name>/src/" subdir
"../DirectCompute/src/<executable_name>/inc/", // up 1 in tree, "/DirectCompute/src/<executable_name>/inc/" subdir
"../../", // up 2 in tree
"../../data/", // up 2 in tree, "/data/" subdir
"../../src/", // up 2 in tree, "/src/" subdir
"../../inc/", // up 2 in tree, "/inc/" subdir
"../../../", // up 3 in tree
"../../../src/<executable_name>/", // up 3 in tree, "/src/<executable_name>/" subdir
"../../../src/<executable_name>/data/", // up 3 in tree, "/src/<executable_name>/data/" subdir
"../../../src/<executable_name>/src/", // up 3 in tree, "/src/<executable_name>/src/" subdir
"../../../src/<executable_name>/inc/", // up 3 in tree, "/src/<executable_name>/inc/" subdir
"../../../sandbox/<executable_name>/", // up 3 in tree, "/sandbox/<executable_name>/" subdir
"../../../sandbox/<executable_name>/data/", // up 3 in tree, "/sandbox/<executable_name>/data/" subdir
"../../../sandbox/<executable_name>/src/", // up 3 in tree, "/sandbox/<executable_name>/src/" subdir
"../../../sandbox/<executable_name>/inc/" // up 3 in tree, "/sandbox/<executable_name>/inc/" subdir
};
// Extract the executable name
std::string executable_name;
if (executable_path != 0)
{
executable_name = std::string(executable_path);
#ifdef _WIN32
// Windows path delimiter
size_t delimiter_pos = executable_name.find_last_of('\\');
executable_name.erase(0, delimiter_pos + 1);
if (executable_name.rfind(".exe") != string::npos)
{
// we strip .exe, only if the .exe is found
executable_name.resize(executable_name.size() - 4);
}
#else
// Linux & OSX path delimiter
size_t delimiter_pos = executable_name.find_last_of('/');
executable_name.erase(0,delimiter_pos+1);
#endif
}
// Loop over all search paths and return the first hit
for( unsigned int i = 0; i < sizeof(searchPath)/sizeof(char*); ++i )
{
std::string path(searchPath[i]);
size_t executable_name_pos = path.find("<executable_name>");
// If there is executable_name variable in the searchPath
// replace it with the value
if(executable_name_pos != std::string::npos)
{
if(executable_path != 0)
{
path.replace(executable_name_pos, strlen("<executable_name>"), executable_name);
}
else
{
// Skip this path entry if no executable argument is given
continue;
}
}
// Test if the file exists
path.append(filename);
std::fstream fh(path.c_str(), std::fstream::in);
if (fh.good())
{
// File found
// returning an allocated array here for backwards compatibility reasons
char* file_path = (char*) malloc(path.length() + 1);
#ifdef _WIN32
strcpy_s(file_path, path.length() + 1, path.c_str());
#else
strcpy(file_path, path.c_str());
#endif
return file_path;
}
}
// File not found
return 0;
}
//////////////////////////////////////////////////////////////////////////////
//! Read file \filename and return the data
//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE
//! @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
//////////////////////////////////////////////////////////////////////////////
template<class T>
shrBOOL
shrReadFile( const char* filename, T** data, unsigned int* len, bool verbose)
{
// check input arguments
ARGCHECK(NULL != filename);
ARGCHECK(NULL != len);
// intermediate storage for the data read
std::vector<T> data_read;
// open file for reading
std::fstream fh( filename, std::fstream::in);
// check if filestream is valid
if(!fh.good())
{
if (verbose)
std::cerr << "shrReadFile() : Opening file failed." << std::endl;
return shrFALSE;
}
// read all data elements
T token;
while( fh.good())
{
fh >> token;
data_read.push_back( token);
}
// the last element is read twice
data_read.pop_back();
// check if reading result is consistent
if( ! fh.eof())
{
if (verbose)
std::cerr << "WARNING : readData() : reading file might have failed."
<< std::endl;
}
fh.close();
// check if the given handle is already initialized
if( NULL != *data)
{
if( *len != data_read.size())
{
std::cerr << "shrReadFile() : Initialized memory given but "
<< "size mismatch with signal read "
<< "(data read / data init = " << (unsigned int)data_read.size()
<< " / " << *len << ")" << std::endl;
return shrFALSE;
}
}
else
{
// allocate storage for the data read
*data = (T*) malloc( sizeof(T) * data_read.size());
// store signal size
*len = static_cast<unsigned int>( data_read.size());
}
// copy data
memcpy( *data, &data_read.front(), sizeof(T) * data_read.size());
return shrTRUE;
}
//////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename
//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
//////////////////////////////////////////////////////////////////////////////
template<class T>
shrBOOL
shrWriteFile( const char* filename, const T* data, unsigned int len,
const T epsilon, bool verbose)
{
ARGCHECK(NULL != filename);
ARGCHECK(NULL != data);
// open file for writing
std::fstream fh( filename, std::fstream::out);
// check if filestream is valid
if(!fh.good())
{
if (verbose)
std::cerr << "shrWriteFile() : Opening file failed." << std::endl;
return shrFALSE;
}
// first write epsilon
fh << "# " << epsilon << "\n";
// write data
for( unsigned int i = 0; (i < len) && (fh.good()); ++i)
{
fh << data[i] << ' ';
}
// Check if writing succeeded
if( ! fh.good())
{
if (verbose)
std::cerr << "shrWriteFile() : Writing file failed." << std::endl;
return shrFALSE;
}
// file ends with nl
fh << std::endl;
return shrTRUE;
}
////////////////////////////////////////////////////////////////////////////////
//! Read file \filename containg single precision floating point data
//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrReadFilef( const char* filename, float** data, unsigned int* len, bool verbose)
{
return shrReadFile( filename, data, len, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Read file \filename containg double precision floating point data
//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrReadFiled( const char* filename, double** data, unsigned int* len, bool verbose)
{
return shrReadFile( filename, data, len, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Read file \filename containg integer data
//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrReadFilei( const char* filename, int** data, unsigned int* len, bool verbose)
{
return shrReadFile( filename, data, len, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Read file \filename containg unsigned integer data
//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrReadFileui( const char* filename, unsigned int** data, unsigned int* len, bool verbose)
{
return shrReadFile( filename, data, len, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Read file \filename containg char / byte data
//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrReadFileb( const char* filename, char** data, unsigned int* len, bool verbose)
{
return shrReadFile( filename, data, len, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Read file \filename containg unsigned char / byte data
//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrReadFileub( const char* filename, unsigned char** data, unsigned int* len, bool verbose)
{
return shrReadFile( filename, data, len, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename for single precision floating point data
//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrWriteFilef( const char* filename, const float* data, unsigned int len,
const float epsilon, bool verbose)
{
return shrWriteFile( filename, data, len, epsilon, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename for double precision floating point data
//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrWriteFiled( const char* filename, const double* data, unsigned int len,
const double epsilon, bool verbose)
{
return shrWriteFile( filename, data, len, epsilon, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename for integer data
//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrWriteFilei( const char* filename, const int* data, unsigned int len, bool verbose)
{
return shrWriteFile( filename, data, len, 0, verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename for unsigned integer data
//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrWriteFileui( const char* filename,const unsigned int* data,unsigned int len, bool verbose)
{
return shrWriteFile( filename, data, len, static_cast<unsigned int>(0), verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename for byte / char data
//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrWriteFileb( const char* filename, const char* data, unsigned int len, bool verbose)
{
return shrWriteFile( filename, data, len, static_cast<char>(0), verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename for byte / char data
//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrWriteFileub( const char* filename, const unsigned char* data,
unsigned int len, bool verbose)
{
return shrWriteFile( filename, data, len, static_cast<unsigned char>(0), verbose);
}
////////////////////////////////////////////////////////////////////////////////
//! Write a data file \filename for unsigned byte / char data
//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE
//! @param filename name of the source file
//! @param data data to write
//! @param len number of data elements in data, -1 on error
//! @param epsilon epsilon for comparison
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrWriteFileb( const char* filename,const unsigned char* data,unsigned int len, bool verbose)
{
return shrWriteFile( filename, data, len, static_cast<unsigned char>(0), verbose);
}
//////////////////////////////////////////////////////////////////////////////
//! Load PGM or PPM file
//! @note if data == NULL then the necessary memory is allocated in the
//! function and w and h are initialized to the size of the image
//! @return shrTRUE if the file loading succeeded, otherwise shrFALSE
//! @param file name of the file to load
//! @param data handle to the memory for the image file data
//! @param w width of the image
//! @param h height of the image
//! @param channels number of channels in image
//////////////////////////////////////////////////////////////////////////////
shrBOOL loadPPM(const char* file, unsigned char** data,
unsigned int *w, unsigned int *h, unsigned int *channels)
{
FILE* fp = 0;
#ifdef _WIN32
// open the file for binary read
errno_t err;
if ((err = fopen_s(&fp, file, "rb")) != 0)
#else
// open the file for binary read
if ((fp = fopen(file, "rb")) == 0)
#endif
{
// if error on attempt to open, be sure the file is null or close it, then return negative error code
if (fp)
{
fclose (fp);
}
std::cerr << "loadPPM() : Failed to open file: " << file << std::endl;
return shrFALSE;
}
// check header
char header[PGMHeaderSize];
if ((fgets( header, PGMHeaderSize, fp) == NULL) && ferror(fp))
{
if (fp)
{
fclose (fp);
}
std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl;
*channels = 0;
return shrFALSE;
}
if (strncmp(header, "P5", 2) == 0)
{
*channels = 1;
}
else if (strncmp(header, "P6", 2) == 0)
{
*channels = 3;
}
else
{
std::cerr << "loadPPM() : File is not a PPM or PGM image" << std::endl;
*channels = 0;
return shrFALSE;
}
// parse header, read maxval, width and height
unsigned int width = 0;
unsigned int height = 0;
unsigned int maxval = 0;
unsigned int i = 0;
while(i < 3)
{
if ((fgets(header, PGMHeaderSize, fp) == NULL) && ferror(fp))
{
if (fp)
{
fclose (fp);
}
std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl;
return shrFALSE;
}
if(header[0] == '#') continue;
#ifdef _WIN32
if(i == 0)
{
i += sscanf_s(header, "%u %u %u", &width, &height, &maxval);
}
else if (i == 1)
{
i += sscanf_s(header, "%u %u", &height, &maxval);
}
else if (i == 2)
{
i += sscanf_s(header, "%u", &maxval);
}
#else
if(i == 0)
{
i += sscanf(header, "%u %u %u", &width, &height, &maxval);
}
else if (i == 1)
{
i += sscanf(header, "%u %u", &height, &maxval);
}
else if (i == 2)
{
i += sscanf(header, "%u", &maxval);
}
#endif
}
// check if given handle for the data is initialized
if(NULL != *data)
{
if (*w != width || *h != height)
{
fclose(fp);
std::cerr << "loadPPM() : Invalid image dimensions." << std::endl;
return shrFALSE;
}
}
else
{
*data = (unsigned char*)malloc( sizeof(unsigned char) * width * height * *channels);
*w = width;
*h = height;
}
// read and close file
if (fread(*data, sizeof(unsigned char), width * height * *channels, fp) != width * height * *channels)
{
fclose(fp);
std::cerr << "loadPPM() : Invalid image." << std::endl;
return shrFALSE;
}
fclose(fp);
return shrTRUE;
}
//////////////////////////////////////////////////////////////////////////////
//! Write / Save PPM or PGM file
//! @note Internal usage only
//! @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
//////////////////////////////////////////////////////////////////////////////
shrBOOL savePPM( const char* file, unsigned char *data,
unsigned int w, unsigned int h, unsigned int channels)
{
ARGCHECK(NULL != data);
ARGCHECK(w > 0);
ARGCHECK(h > 0);
std::fstream fh( file, std::fstream::out | std::fstream::binary );
if( fh.bad())
{
std::cerr << "savePPM() : Opening file failed." << std::endl;
return shrFALSE;
}
if (channels == 1)
{
fh << "P5\n";
}
else if (channels == 3) {
fh << "P6\n";
}
else {
std::cerr << "savePPM() : Invalid number of channels." << std::endl;
return shrFALSE;
}
fh << w << "\n" << h << "\n" << 0xff << std::endl;
for( unsigned int i = 0; (i < (w*h*channels)) && fh.good(); ++i)
{
fh << data[i];
}
fh.flush();
if( fh.bad())
{
std::cerr << "savePPM() : Writing data failed." << std::endl;
return shrFALSE;
}
fh.close();
return shrTRUE;
}
////////////////////////////////////////////////////////////////////////////////
//! Load PPM image file (with unsigned char as data element type), padding 4th component
//! @return shrTrue if reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrLoadPPM4ub( const char* file, unsigned char** OutData,
unsigned int *w, unsigned int *h)
{
// Load file data into a temporary buffer with automatic allocation
unsigned char* cLocalData = 0;
unsigned int channels;
shrBOOL bLoadOK = loadPPM(file, &cLocalData, w, h, &channels); // this allocates cLocalData, which must be freed later
// If the data loaded OK from file to temporary buffer, then go ahead with padding and transfer
if (shrTRUE == bLoadOK)
{
// if the receiving buffer is null, allocate it... caller must free this
int size = *w * *h;
if (*OutData == NULL)
{
*OutData = (unsigned char*)malloc(sizeof(unsigned char) * size * 4);
}
// temp pointers for incrementing
unsigned char* cTemp = cLocalData;
unsigned char* cOutPtr = *OutData;
// transfer data, padding 4th element
for(int i=0; i<size; i++)
{
*cOutPtr++ = *cTemp++;
*cOutPtr++ = *cTemp++;
*cOutPtr++ = *cTemp++;
*cOutPtr++ = 0;
}
// free temp lcoal buffer and return OK
free(cLocalData);
return shrTRUE;
}
else
{
// image wouldn't load
free(cLocalData);
return shrFALSE;
}
}
////////////////////////////////////////////////////////////////////////////////
//! Save PPM image file (with unsigned char as data element type, padded to 4 byte)
//! @return shrTrue if reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrSavePPM4ub( const char* file, unsigned char *data,
unsigned int w, unsigned int h)
{
// strip 4th component
int size = w * h;
unsigned char *ndata = (unsigned char*) malloc( sizeof(unsigned char) * size*3);
unsigned char *ptr = ndata;
for(int i=0; i<size; i++) {
*ptr++ = *data++;
*ptr++ = *data++;
*ptr++ = *data++;
data++;
}
shrBOOL succ = savePPM(file, ndata, w, h, 3);
free(ndata);
return succ;
}
////////////////////////////////////////////////////////////////////////////////
//! 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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrSavePGMub( const char* file, unsigned char *data,
unsigned int w, unsigned int h)
{
return savePPM( file, data, w, h, 1);
}
////////////////////////////////////////////////////////////////////////////////
//! Load PGM image file (with unsigned char as data element type)
//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrLoadPGMub( const char* file, unsigned char** data,
unsigned int *w,unsigned int *h)
{
unsigned int channels;
return loadPPM( file, data, w, h, &channels);
}
////////////////////////////////////////////////////////////////////////////////
//! Check if command line argument \a flag-name is given
//! @return shrTRUE if command line argument \a flag_name has been given, otherwise shrFALSE
//! @param argc argc as passed to main()
//! @param argv argv as passed to main()
//! @param flag_name name of command line flag
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrCheckCmdLineFlag( const int argc, const char** argv, const char* flag_name)
{
shrBOOL ret_val = shrFALSE;
try
{
// initalize
CmdArgReader::init( argc, argv);
// check if the command line argument exists
if( CmdArgReader::existArg( flag_name))
{
ret_val = shrTRUE;
}
}
catch( const std::exception& /*ex*/)
{
std::cerr << "Error when parsing command line argument string." << std::endl;
}
return ret_val;
}
////////////////////////////////////////////////////////////////////////////////
//! Get the value of a command line argument of type int
//! @return shrTRUE if command line argument \a arg_name has been given and
//! is of the requested type, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrGetCmdLineArgumenti( const int argc, const char** argv,
const char* arg_name, int* val)
{
shrBOOL ret_val = shrFALSE;
try
{
// initialize
CmdArgReader::init( argc, argv);
// access argument
const int* v = CmdArgReader::getArg<int>( arg_name);
if( NULL != v)
{
// assign value
*val = *v;
ret_val = shrTRUE;
}
else {
// fail safe
val = NULL;
}
}
catch( const std::exception& /*ex*/)
{
std::cerr << "Error when parsing command line argument string." << std::endl;
}
return ret_val;
}
////////////////////////////////////////////////////////////////////////////////
//! Get the value of a command line argument of type unsigned int
//! @return shrTRUE if command line argument \a arg_name has been given and
//! is of the requested type, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrGetCmdLineArgumentu( const int argc, const char** argv,
const char* arg_name, unsigned int* val)
{
shrBOOL ret_val = shrFALSE;
try
{
// initialize
CmdArgReader::init( argc, argv);
// access argument
const int* v = CmdArgReader::getArg<int>( arg_name);
if( NULL != v)
{
// assign value
*val = *v;
ret_val = shrTRUE;
}
else {
// fail safe
val = NULL;
}
}
catch( const std::exception& /*ex*/)
{
std::cerr << "Error when parsing command line argument string." << std::endl;
}
return ret_val;
}
////////////////////////////////////////////////////////////////////////////////
//! Get the value of a command line argument of type float
//! @return shrTRUE if command line argument \a arg_name has been given and
//! is of the requested type, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrGetCmdLineArgumentf( const int argc, const char** argv,
const char* arg_name, float* val)
{
shrBOOL ret_val = shrFALSE;
try
{
// initialize
CmdArgReader::init( argc, argv);
// access argument
const float* v = CmdArgReader::getArg<float>( arg_name);
if( NULL != v)
{
// assign value
*val = *v;
ret_val = shrTRUE;
}
else {
// fail safe
val = NULL;
}
}
catch( const std::exception& /*ex*/)
{
std::cerr << "Error when parsing command line argument string." << std::endl;
}
return ret_val;
}
////////////////////////////////////////////////////////////////////////////////
//! Get the value of a command line argument of type string
//! @return shrTRUE if command line argument \a arg_name has been given and
//! is of the requested type, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrGetCmdLineArgumentstr( const int argc, const char** argv,
const char* arg_name, char** val)
{
shrBOOL ret_val = shrFALSE;
try
{
// initialize
CmdArgReader::init( argc, argv);
// access argument
const std::string* v = CmdArgReader::getArg<std::string>( arg_name);
if( NULL != v)
{
// allocate memory for the string
*val = (char*)malloc(sizeof(char) * (v->length() + 1));
// copy from string to c_str
#ifdef WIN32
strcpy_s(*val, v->length() + 1, v->c_str());
#else
strcpy(*val, v->c_str());
#endif
ret_val = shrTRUE;
}
else {
// fail safe
*val = NULL;
}
}
catch( const std::exception& /*ex*/)
{
std::cerr << "Error when parsing command line argument string."<<
std::endl;
}
return ret_val;
}
//////////////////////////////////////////////////////////////////////////////
//! Compare two arrays of arbitrary type
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
//////////////////////////////////////////////////////////////////////////////
template<class T, class S>
shrBOOL
compareData( const T* reference, const T* data, const unsigned int len,
const S epsilon, const float threshold)
{
ARGCHECK( epsilon >= 0);
bool result = true;
unsigned int error_count = 0;
for( unsigned int i = 0; i < len; ++i) {
T diff = reference[i] - data[i];
bool comp = (diff <= epsilon) && (diff >= -epsilon);
result &= comp;
error_count += !comp;
#ifdef _DEBUG
if( ! comp)
{
std::cerr << "ERROR, i = " << i << ",\t "
<< reference[i] << " / "
<< data[i]
<< " (reference / data)\n";
}
#endif
}
if (threshold == 0.0f) {
return (result) ? shrTRUE : shrFALSE;
} else {
return (len*threshold > error_count) ? shrTRUE : shrFALSE;
}
}
//////////////////////////////////////////////////////////////////////////////
//! Compare two arrays of arbitrary type
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
//////////////////////////////////////////////////////////////////////////////
template<class T, class S>
shrBOOL
compareDataAsFloat( const T* reference, const T* data, const unsigned int len,
const S epsilon)
{
ARGCHECK(epsilon >= 0);
// If we set epsilon to be 0, let's set a minimum threshold
float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR );
int error_count = 0;
bool result = true;
for( unsigned int i = 0; i < len; ++i) {
float diff = fabs((float)reference[i] - (float)data[i]);
bool comp = (diff < max_error);
result &= comp;
if( ! comp)
{
error_count++;
#ifdef _DEBUG
if (error_count < 50) {
shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)0x%02x / (data)0x%02x / (diff)%d\n", max_error, i, reference[i], data[i], (unsigned int)diff);
}
#endif
}
}
if (error_count) {
shrLog("\n Total # of errors = %d\n", error_count);
}
return (error_count == 0) ? shrTRUE : shrFALSE;
}
//////////////////////////////////////////////////////////////////////////////
//! Compare two arrays of arbitrary type
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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 epsilon threshold % of (# of bytes) for pass/fail
//////////////////////////////////////////////////////////////////////////////
template<class T, class S>
shrBOOL
compareDataAsFloatThreshold( const T* reference, const T* data, const unsigned int len,
const S epsilon, const float threshold)
{
ARGCHECK(epsilon >= 0);
// If we set epsilon to be 0, let's set a minimum threshold
float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR);
int error_count = 0;
bool result = true;
for( unsigned int i = 0; i < len; ++i) {
float diff = fabs((float)reference[i] - (float)data[i]);
bool comp = (diff < max_error);
result &= comp;
if( ! comp)
{
error_count++;
//#ifdef _DEBUG
if (error_count < 50) {
shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)%f / (data)%f / (diff)%f\n", max_error, i, reference[i], data[i], diff);
}
//#endif
}
}
if (threshold == 0.0f) {
if (error_count) {
shrLog("\n Total # of errors = %d\n", error_count);
}
return (error_count == 0) ? shrTRUE : shrFALSE;
} else {
if (error_count) {
shrLog("\n %.2f(%%) of bytes mismatched (count=%d)\n", (float)error_count*100/(float)len, error_count);
}
return ((len*threshold > error_count) ? shrTRUE : shrFALSE);
}
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two float arrays
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrComparef( const float* reference, const float* data,
const unsigned int len )
{
const float epsilon = 0.0;
return compareData( reference, data, len, epsilon, 0.0f );
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two integer arrays
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrComparei( const int* reference, const int* data,
const unsigned int len )
{
const int epsilon = 0;
return compareData( reference, data, len, epsilon, 0.0f);
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two unsigned integer arrays, with epsilon and threshold
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrCompareuit( const unsigned int* reference, const unsigned int* data,
const unsigned int len, const float epsilon, const float threshold )
{
return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold );
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two integer arrays
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrCompareub( const unsigned char* reference, const unsigned char* data,
const unsigned int len )
{
const int epsilon = 0;
return compareData( reference, data, len, epsilon, 0.0f);
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two integer arrays (inc Threshold for # of pixel we can have errors)
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrCompareubt( const unsigned char* reference, const unsigned char* data,
const unsigned int len, const float epsilon, const float threshold )
{
return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold );
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two integer arrays
//! @return shrTRUE if \a reference and \a data are identical,
//! otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrCompareube( const unsigned char* reference, const unsigned char* data,
const unsigned int len, const float epsilon )
{
return compareDataAsFloat( reference, data, len, epsilon );
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two float arrays with an epsilon tolerance for equality
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrComparefe( const float* reference, const float* data,
const unsigned int len, const float epsilon )
{
return compareData( reference, data, len, epsilon, 0.0f);
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two float arrays with an epsilon tolerance for equality and a
//! threshold for # pixel errors
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrComparefet( const float* reference, const float* data,
const unsigned int len, const float epsilon, const float threshold )
{
return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold );
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two float arrays using L2-norm with an epsilon tolerance for equality
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrCompareL2fe( const float* reference, const float* data,
const unsigned int len, const float epsilon )
{
ARGCHECK(epsilon >= 0);
float error = 0;
float ref = 0;
for( unsigned int i = 0; i < len; ++i) {
float diff = reference[i] - data[i];
error += diff * diff;
ref += reference[i] * reference[i];
}
float normRef = sqrtf(ref);
if (fabs(ref) < 1e-7) {
#ifdef _DEBUG
std::cerr << "ERROR, reference l2-norm is 0\n";
#endif
return shrFALSE;
}
float normError = sqrtf(error);
error = normError / normRef;
bool result = error < epsilon;
#ifdef _DEBUG
if( ! result)
{
std::cerr << "ERROR, l2-norm error "
<< error << " is greater than epsilon " << epsilon << "\n";
}
#endif
return result ? shrTRUE : shrFALSE;
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two PPM image files with an epsilon tolerance for equality
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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::cerr
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold)
{
unsigned char* src_data = NULL;
unsigned char* ref_data = NULL;
unsigned long error_count = 0;
unsigned int ref_width, ref_height;
unsigned int src_width, src_height;
// Check sample and reference file pointers
if (src_file == NULL || ref_file == NULL) {
shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n");
return shrFALSE;
}
shrLog("\n> shrComparePPM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file);
// Load the ref image file
if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE)
{
shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file);
return shrFALSE;
}
// Load the sample image file
if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE)
{
shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file);
return shrFALSE;
}
// check to see if image dimensions match
if(src_height != ref_height || src_width != ref_width)
{
shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ",
src_width, src_height, ref_width, ref_height);
return shrFALSE;
}
// compare the images
if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE)
{
error_count=1;
}
shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!");
return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass
}
////////////////////////////////////////////////////////////////////////////////
//! Compare two PGM image files with an epsilon tolerance for equality
//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE
//! @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)
////////////////////////////////////////////////////////////////////////////////
shrBOOL shrComparePGM( const char *src_file, const char *ref_file, const float epsilon, const float threshold)
{
unsigned char* src_data = NULL;
unsigned char* ref_data = NULL;
unsigned long error_count = 0;
unsigned int ref_width, ref_height;
unsigned int src_width, src_height;
// Check sample and reference file pointers
if (src_file == NULL || ref_file == NULL) {
shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n");
return shrFALSE;
}
shrLog("\n> shrComparePGM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file);
// Load the ref image file
if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE)
{
shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file);
return shrFALSE;
}
// Load the sample image file
if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE)
{
shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file);
return shrFALSE;
}
// check to see if image dimensions match
if(src_height != ref_height || src_width != ref_width)
{
shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ",
src_width, src_height, ref_width, ref_height);
return shrFALSE;
}
// compare the images
if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE)
{
error_count=1;
}
shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!");
return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass
}
// Load raw data from disk
unsigned char* shrLoadRawFile(const char* filename, size_t size)
{
FILE *fp = NULL;
#ifdef WIN32
errno_t err;
if ((err = fopen_s(&fp, filename, "rb")) != 0)
#else
if ((fp = fopen(filename, "rb")) == NULL)
#endif
{
shrLog(" Error opening file '%s' !!!\n", filename);
return 0;
}
unsigned char* data = (unsigned char*)malloc(size);
size_t read = fread(data, 1, size, fp);
fclose(fp);
shrLog(" Read '%s', %d bytes\n", filename, read);
return data;
}
// Round Up Division function
size_t shrRoundUp(int group_size, int global_size)
{
int r = global_size % group_size;
if(r == 0)
{
return global_size;
} else
{
return global_size + group_size - r;
}
}