mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-13 19:17:12 +00:00
Initial commit of existing code.
* All renderdoc code up to this point was written by me, history is available by request
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Crytek
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os/os_specific.h"
|
||||
#include "common/threading.h"
|
||||
|
||||
#include "string_utils.h"
|
||||
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
||||
template<> const wchar_t* pathSeparator() { return L"\\/"; }
|
||||
template<> const char* pathSeparator() { return "\\/"; }
|
||||
|
||||
template<> const wchar_t* curdir() { return L"."; }
|
||||
template<> const char* curdir() { return "."; }
|
||||
|
||||
std::wstring widen(std::string str)
|
||||
{
|
||||
return std::wstring(str.begin(), str.end());
|
||||
}
|
||||
|
||||
std::string narrow(std::wstring str)
|
||||
{
|
||||
return std::string(str.begin(), str.end());
|
||||
}
|
||||
|
||||
void rdcassert(const char *condition, const char *file, unsigned int line, const char *func)
|
||||
{
|
||||
rdclog_int(RDCLog_Error, file, line, "Assertion failed: '%hs'", condition, file, line);
|
||||
}
|
||||
|
||||
static wstring &logfile()
|
||||
{
|
||||
static wstring fn;
|
||||
return fn;
|
||||
}
|
||||
|
||||
const wchar_t *rdclog_getfilename()
|
||||
{
|
||||
return logfile().c_str();
|
||||
}
|
||||
|
||||
void rdclog_filename(const wchar_t *filename)
|
||||
{
|
||||
logfile() = L"";
|
||||
if(filename && filename[0])
|
||||
logfile() = filename;
|
||||
}
|
||||
|
||||
void rdclog_delete()
|
||||
{
|
||||
if(!logfile().empty())
|
||||
FileIO::UnlinkFileW(logfile().c_str());
|
||||
}
|
||||
|
||||
void rdclog_flush()
|
||||
{
|
||||
}
|
||||
|
||||
void rdclog_int(LogType type, const char *file, unsigned int line, const char *fmt, ...)
|
||||
{
|
||||
if(type <= RDCLog_First || type >= RDCLog_NumTypes)
|
||||
{
|
||||
RDCFATAL("Unexpected log type");
|
||||
return;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
const char *name = "RENDERDOC: ";
|
||||
|
||||
char timestamp[64] = {0};
|
||||
#if defined(INCLUDE_TIMESTAMP_IN_LOG)
|
||||
StringFormat::sntimef(timestamp, 63, "[%H:%M:%S] ");
|
||||
#endif
|
||||
|
||||
char location[64] = {0};
|
||||
#if defined(INCLUDE_LOCATION_IN_LOG)
|
||||
string loc;
|
||||
loc = basename(string(file));
|
||||
StringFormat::snprintf(location, 63, "% 20s(%4d) - ", loc.c_str(), line);
|
||||
#endif
|
||||
|
||||
const char *typestr[RDCLog_NumTypes] = {
|
||||
"Debug ",
|
||||
"Log ",
|
||||
"Warning",
|
||||
"Error ",
|
||||
"Fatal ",
|
||||
};
|
||||
|
||||
const size_t outBufSize = 4*1024;
|
||||
char outputBuffer[outBufSize+1];
|
||||
outputBuffer[outBufSize] = 0;
|
||||
|
||||
char *output = outputBuffer;
|
||||
size_t available = outBufSize;
|
||||
|
||||
int numWritten = StringFormat::snprintf(output, available, "%hs %hs%hs%hs - ", name, timestamp, location, typestr[type]);
|
||||
|
||||
if(numWritten < 0)
|
||||
{
|
||||
va_end(args);
|
||||
return;
|
||||
}
|
||||
|
||||
output += numWritten;
|
||||
available -= numWritten;
|
||||
|
||||
numWritten = StringFormat::vsnprintf(output, available, fmt, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
if(numWritten < 0)
|
||||
return;
|
||||
|
||||
output += numWritten;
|
||||
available -= numWritten;
|
||||
|
||||
if(available < 2)
|
||||
return;
|
||||
|
||||
*output = '\n';
|
||||
*(output+1) = 0;
|
||||
|
||||
{
|
||||
static Threading::CriticalSection lock;
|
||||
|
||||
SCOPED_LOCK(lock);
|
||||
|
||||
#if defined(OUTPUT_LOG_TO_DEBUG_OUT)
|
||||
OSUtility::DebugOutputA(outputBuffer);
|
||||
#endif
|
||||
#if defined(OUTPUT_LOG_TO_STDOUT)
|
||||
fprintf(stdout, "%hs", outputBuffer); fflush(stdout);
|
||||
#endif
|
||||
#if defined(OUTPUT_LOG_TO_STDERR)
|
||||
fprintf(stderr, "%hs", outputBuffer); fflush(stderr);
|
||||
#endif
|
||||
#if defined(OUTPUT_LOG_TO_DISK)
|
||||
if(!logfile().empty())
|
||||
{
|
||||
FILE *f = FileIO::fopen(logfile().c_str(), L"a");
|
||||
if(f)
|
||||
{
|
||||
FileIO::fwrite(outputBuffer, 1, strlen(outputBuffer), f);
|
||||
FileIO::fclose(f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Crytek
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "globalconfig.h"
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Utility macros
|
||||
|
||||
#ifndef SAFE_DELETE
|
||||
#define SAFE_DELETE(p) do { if (p) { delete (p); (p)=NULL; } } while(0)
|
||||
#endif
|
||||
|
||||
#ifndef SAFE_DELETE_ARRAY
|
||||
#define SAFE_DELETE_ARRAY(p) do { if (p) { delete[] (p); (p)=NULL; } } while(0)
|
||||
#endif
|
||||
|
||||
#ifndef SAFE_ADDREF
|
||||
#define SAFE_ADDREF(p) do { if (p) { (p)->AddRef(); } } while(0)
|
||||
#endif
|
||||
|
||||
#ifndef SAFE_RELEASE
|
||||
#define SAFE_RELEASE(p) do { if (p) { (p)->Release(); (p)=NULL; } } while(0)
|
||||
#define SAFE_RELEASE_NOCLEAR(p) do { if (p) { (p)->Release(); } } while(0)
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_COUNT
|
||||
#define ARRAY_COUNT(arr) (sizeof(arr)/sizeof(arr[0]))
|
||||
#endif
|
||||
|
||||
#define RANDF(mn, mx) ((float(rand())/float(RAND_MAX))*((mx)-(mn))+(mn))
|
||||
|
||||
#define STRINGIZE2(a) #a
|
||||
#define STRINGIZE(a) STRINGIZE2(a)
|
||||
|
||||
#define CONCAT2(a, b) a##b
|
||||
#define CONCAT(a, b) CONCAT2(a, b)
|
||||
|
||||
#define WIDEN2(x) L ## x
|
||||
#define WIDEN(x) WIDEN2(x)
|
||||
|
||||
#include "os/os_specific.h"
|
||||
|
||||
#define RDCEraseMem(a, b) memset(a, 0, b)
|
||||
#define RDCEraseEl(a) memset(&a, 0, sizeof(a))
|
||||
|
||||
template<typename T>
|
||||
T RDCCLAMP(const T &val, const T &mn, const T &mx) { return val < mn ? mn : (val > mx ? mx : val); }
|
||||
|
||||
template<typename T>
|
||||
T RDCMIN(const T &a, const T &b) { return a < b ? a : b; }
|
||||
|
||||
template<typename T>
|
||||
T RDCMAX(const T &a, const T &b) { return a > b ? a : b; }
|
||||
|
||||
template<typename T>
|
||||
inline T AlignUp4(T x) { return (x+0x3) & (~0x3); }
|
||||
|
||||
template<typename T>
|
||||
inline T AlignUp16(T x) { return (x+0xf) & (~0xf); }
|
||||
|
||||
#define MAKE_FOURCC(a, b, c, d) (((uint32_t)(d) << 24) | ((uint32_t)(c) << 16) | ((uint32_t)(b) << 8) | (uint32_t)(a))
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Debugging features
|
||||
|
||||
#define RDCDUMP() do { OSUtility::ForceCrash(); } while(0)
|
||||
|
||||
#if !defined(RELEASE) || defined(FORCE_DEBUGBREAK)
|
||||
#define RDCBREAK() do { if(OSUtility::DebuggerPresent()) OSUtility::DebugBreak(); else RDCDUMP(); } while(0)
|
||||
#else
|
||||
#define RDCBREAK() do { } while(0)
|
||||
#endif
|
||||
|
||||
#define RDCUNIMPLEMENTED(...) do { rdclog(RDCLog_Warning, "Unimplemented: " __VA_ARGS__); RDCBREAK(); } while(0)
|
||||
|
||||
//
|
||||
// Logging
|
||||
//
|
||||
|
||||
enum LogType
|
||||
{
|
||||
RDCLog_First = -1,
|
||||
RDCLog_Debug,
|
||||
RDCLog_Comment,
|
||||
RDCLog_Warning,
|
||||
RDCLog_Error,
|
||||
RDCLog_Fatal,
|
||||
RDCLog_NumTypes,
|
||||
};
|
||||
|
||||
#if defined(STRIP_LOG)
|
||||
#define RDCLOGFILE(fn) do { } while(0)
|
||||
#define RDCLOGDELETE() do { } while(0)
|
||||
|
||||
#define RDCDEBUG(...) do { } while(0)
|
||||
#define RDCLOG(...) do { } while(0)
|
||||
#define RDCWARN(...) do { } while(0)
|
||||
#define RDCERR(...) do { } while(0)
|
||||
#define RDCFATAL(...) do { RDCDUMP(); exit(0); } while(0)
|
||||
#else
|
||||
void rdclog_flush();
|
||||
void rdclog_int(LogType type, const char *file, unsigned int line, const char *fmt, ...);
|
||||
|
||||
#define rdclog(type, ...) rdclog_int(type, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
const wchar_t *rdclog_getfilename();
|
||||
void rdclog_filename(const wchar_t *filename);
|
||||
void rdclog_delete();
|
||||
|
||||
#define RDCLOGFILE(fn) rdclog_filename(fn)
|
||||
#define RDCGETLOGFILE() rdclog_getfilename()
|
||||
#define RDCLOGDELETE() rdclog_delete()
|
||||
|
||||
#if ( !defined(RELEASE) || defined(FORCE_DEBUG_LOGS) ) && !defined(STRIP_DEBUG_LOGS)
|
||||
#define RDCDEBUG(...) rdclog(RDCLog_Debug, __VA_ARGS__)
|
||||
#else
|
||||
#define RDCDEBUG(...) do { } while(0)
|
||||
#endif
|
||||
|
||||
#define RDCLOG(...) rdclog(RDCLog_Comment, __VA_ARGS__)
|
||||
#define RDCWARN(...) rdclog(RDCLog_Warning, __VA_ARGS__)
|
||||
|
||||
#if defined(DEBUGBREAK_ON_ERROR_LOG)
|
||||
#define RDCERR(...) do { rdclog(RDCLog_Error, __VA_ARGS__); rdclog_flush(); RDCBREAK(); } while(0)
|
||||
#else
|
||||
#define RDCERR(...) rdclog(RDCLog_Error, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define RDCFATAL(...) do { rdclog(RDCLog_Fatal, __VA_ARGS__); rdclog_flush(); RDCDUMP(); exit(0); } while(0)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Assert
|
||||
//
|
||||
|
||||
#if !defined(RELEASE) || defined(FORCE_ASSERTS)
|
||||
void rdcassert(const char *condition, const char *file, unsigned int line, const char *func);
|
||||
|
||||
#define RDCASSERT(cond) do { if(!(cond)) { rdcassert(#cond, __FILE__, __LINE__, __PRETTY_FUNCTION_SIGNATURE__); rdclog_flush(); RDCBREAK(); } } while(0)
|
||||
#else
|
||||
#define RDCASSERT(cond) do { } while(0)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Compile asserts
|
||||
//
|
||||
|
||||
#if defined(STRIP_COMPILE_ASSERTS)
|
||||
#define RDCCOMPILE_ASSERT(condition, message) do { } while(0)
|
||||
#else
|
||||
#define RDCCOMPILE_ASSERT(condition, message) static_assert(condition, message)
|
||||
#endif
|
||||
|
||||
typedef unsigned char byte;
|
||||
@@ -0,0 +1,95 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Crytek
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Global constants
|
||||
enum
|
||||
{
|
||||
RenderDoc_FirstCaptureNetworkPort = 38920,
|
||||
RenderDoc_LastCaptureNetworkPort = RenderDoc_FirstCaptureNetworkPort + 7,
|
||||
RenderDoc_ReplayNetworkPort = 39920,
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Debugging features configuration
|
||||
|
||||
// remove all logging code
|
||||
//#define STRIP_LOG
|
||||
|
||||
// remove all compile time asserts. Normally done even in release
|
||||
// but this would speed up compilation
|
||||
//#define STRIP_COMPILE_ASSERTS
|
||||
|
||||
// force asserts regardless of debug/release mode
|
||||
#define FORCE_ASSERTS
|
||||
|
||||
// force debugbreaks regardless of debug/release mode
|
||||
//#define FORCE_DEBUGBREAK
|
||||
|
||||
// synchronously (ie. flushed to disk) write out the text-mode only serialised
|
||||
// data of ALL serialising. Helps in debugging crashes to know exactly which
|
||||
// calls have been made
|
||||
//#define DEBUG_TEXT_SERIALISER
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Logging configuration
|
||||
|
||||
// error logs trigger a breakpoint
|
||||
#define DEBUGBREAK_ON_ERROR_LOG
|
||||
|
||||
// whether to include timestamp on log lines
|
||||
#define INCLUDE_TIMESTAMP_IN_LOG
|
||||
|
||||
// whether to include file and line on log lines
|
||||
#define INCLUDE_LOCATION_IN_LOG
|
||||
|
||||
// logs go to stdout/stderr
|
||||
#define OUTPUT_LOG_TO_STDOUT
|
||||
//#define OUTPUT_LOG_TO_STDERR
|
||||
|
||||
// logs go to debug output (visual studio output window)
|
||||
#define OUTPUT_LOG_TO_DEBUG_OUT
|
||||
|
||||
// logs go to disk
|
||||
#define OUTPUT_LOG_TO_DISK
|
||||
|
||||
// normally only in a debug build do we
|
||||
// include debug logs. This prints them all the time
|
||||
//#define FORCE_DEBUG_LOGS
|
||||
// this strips them completely
|
||||
//#define STRIP_DEBUG_LOGS
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// optional features
|
||||
|
||||
#if defined(NVIDIA_PERFKIT_DIR)
|
||||
#define ENABLE_NVIDIA_PERFKIT
|
||||
#endif
|
||||
|
||||
#if defined(AMD_PERFAPI_DIR)
|
||||
#define ENABLE_AMD_PERFAPI
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Crytek
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
using std::basic_string;
|
||||
using std::vector;
|
||||
|
||||
// in common.cpp
|
||||
template<class charType> const charType* pathSeparator();
|
||||
template<class charType> const charType* curdir();
|
||||
|
||||
template<class strType> strType basename(const strType &path)
|
||||
{
|
||||
strType base = path;
|
||||
|
||||
if(base.length() == 0)
|
||||
return base;
|
||||
|
||||
if(base[base.length()-1] == '/' || base[base.length()-1] == '\\')
|
||||
base.erase(base.size()-1);
|
||||
|
||||
size_t offset = base.find_last_of(pathSeparator<typename strType::value_type>());
|
||||
|
||||
if(offset == strType::npos)
|
||||
return base;
|
||||
|
||||
return base.substr(offset+1);
|
||||
}
|
||||
|
||||
template<class strType> strType dirname(const strType &path)
|
||||
{
|
||||
strType base = path;
|
||||
|
||||
if(base.length() == 0)
|
||||
return base;
|
||||
|
||||
if(base[base.length()-1] == '/' || base[base.length()-1] == '\\')
|
||||
base.erase(base.size()-1);
|
||||
|
||||
size_t offset = base.find_last_of(pathSeparator<typename strType::value_type>());
|
||||
|
||||
if(offset == strType::npos)
|
||||
return curdir<typename strType::value_type>();
|
||||
|
||||
return base.substr(0, offset);
|
||||
}
|
||||
|
||||
template <class CharType>
|
||||
void strreplace(basic_string<CharType>& str, const basic_string<CharType>& toFind, const basic_string<CharType>& replacement, typename basic_string<CharType>::size_type index = 0)
|
||||
{
|
||||
typename basic_string<CharType>::size_type length = toFind.length();
|
||||
|
||||
while(index < str.length())
|
||||
{
|
||||
index = str.find(toFind, index);
|
||||
|
||||
if(index < str.length())
|
||||
{
|
||||
str.replace(index, length, replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CharType>
|
||||
basic_string<CharType> strlower(const basic_string<CharType>& str)
|
||||
{
|
||||
basic_string<CharType> newstr(str);
|
||||
transform(newstr.begin(), newstr.end(), newstr.begin(), tolower);
|
||||
return newstr;
|
||||
}
|
||||
|
||||
template <typename CharType>
|
||||
basic_string<CharType> strupper(const basic_string<CharType>& str)
|
||||
{
|
||||
basic_string<CharType> newstr(str);
|
||||
transform(newstr.begin(), newstr.end(), newstr.begin(), (int(*)(int))toupper);
|
||||
return newstr;
|
||||
}
|
||||
|
||||
template <class CharType>
|
||||
void split(const basic_string<CharType>& in, vector<basic_string<CharType> >& out, const CharType sep)
|
||||
{
|
||||
basic_string<CharType> work = in;
|
||||
typename basic_string<CharType>::size_type offset = work.find(sep);
|
||||
|
||||
while(offset != basic_string<CharType>::npos)
|
||||
{
|
||||
out.push_back(work.substr(0, offset));
|
||||
work = work.substr(offset+1);
|
||||
|
||||
offset = work.find(sep);
|
||||
}
|
||||
|
||||
if(work.size() && work[0] != 0)
|
||||
out.push_back(work);
|
||||
}
|
||||
|
||||
template <class CharType>
|
||||
void merge(const vector<basic_string<CharType> >& in, basic_string<CharType>& out, const CharType sep)
|
||||
{
|
||||
out = basic_string<CharType>();
|
||||
for(size_t i=0; i < in.size(); i++)
|
||||
{
|
||||
out += in[i];
|
||||
out += sep;
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring widen(std::string str);
|
||||
std::string narrow(std::wstring str);
|
||||
@@ -0,0 +1,67 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Crytek
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "os/os_specific.h"
|
||||
|
||||
namespace Threading
|
||||
{
|
||||
|
||||
class ScopedLock
|
||||
{
|
||||
public:
|
||||
ScopedLock(CriticalSection &cs)
|
||||
: m_CS(&cs)
|
||||
{ m_CS->Lock(); }
|
||||
~ScopedLock()
|
||||
{ m_CS->Unlock(); }
|
||||
|
||||
private:
|
||||
CriticalSection *m_CS;
|
||||
};
|
||||
|
||||
class TryScopedLock
|
||||
{
|
||||
public:
|
||||
TryScopedLock(CriticalSection &cs)
|
||||
: m_CS(&cs)
|
||||
{ m_Owned = m_CS->Trylock(); }
|
||||
~TryScopedLock()
|
||||
{ if(m_Owned) m_CS->Unlock(); }
|
||||
|
||||
bool HasLock()
|
||||
{
|
||||
return m_Owned;
|
||||
}
|
||||
|
||||
private:
|
||||
CriticalSection *m_CS;
|
||||
bool m_Owned;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#define SCOPED_LOCK(cs) Threading::ScopedLock CONCAT(scopedlock, __LINE__)(cs);
|
||||
@@ -0,0 +1,93 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Crytek
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "os/os_specific.h"
|
||||
|
||||
class PerformanceTimer
|
||||
{
|
||||
public:
|
||||
PerformanceTimer()
|
||||
{
|
||||
m_CounterFrequency = Timing::GetTickFrequency();
|
||||
|
||||
Restart();
|
||||
}
|
||||
|
||||
double GetMilliseconds()
|
||||
{
|
||||
return double(Timing::GetTick()-m_Start)/m_CounterFrequency;
|
||||
}
|
||||
|
||||
void Restart()
|
||||
{
|
||||
m_Start = Timing::GetTick();
|
||||
}
|
||||
|
||||
private:
|
||||
double m_CounterFrequency;
|
||||
uint64_t m_Start;
|
||||
};
|
||||
|
||||
class ScopedTimer
|
||||
{
|
||||
public:
|
||||
ScopedTimer(const char *file, unsigned int line, const char *fmt, ...)
|
||||
{
|
||||
m_File = file;
|
||||
m_Line = line;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
char buf[1024];
|
||||
buf[1023] = 0;
|
||||
StringFormat::vsnprintf(buf, 1023, fmt, args);
|
||||
|
||||
m_Message = buf;
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
~ScopedTimer()
|
||||
{
|
||||
rdclog_int(RDCLog_Comment, m_File, m_Line, "Timer %hs - %.3lf ms", m_Message.c_str(), m_Timer.GetMilliseconds());
|
||||
}
|
||||
private:
|
||||
const char *m_File;
|
||||
unsigned int m_Line;
|
||||
string m_Message;
|
||||
PerformanceTimer m_Timer;
|
||||
};
|
||||
|
||||
#define SCOPED_TIMER(...) ScopedTimer CONCAT(timer, __LINE__) (__FILE__, __LINE__, __VA_ARGS__);
|
||||
@@ -0,0 +1,263 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Crytek
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "threading.h"
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
#define INCLUDE_TYPE_NAMES
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_TYPE_NAMES
|
||||
template<class T> class GetTypeName { public: static const char *Name(); };
|
||||
#endif
|
||||
|
||||
template<class C> class FriendMaker { public: typedef C Type; };
|
||||
|
||||
// allocate each class in its own pool so we can identify the type by the pointer
|
||||
template<typename WrapType, int PoolCount = 8192, int MaxPoolByteSize = 1024*1024>
|
||||
class WrappingPool
|
||||
{
|
||||
public:
|
||||
void *Allocate()
|
||||
{
|
||||
SCOPED_LOCK(m_Lock);
|
||||
|
||||
// try and allocate from immediate pool
|
||||
void *ret = m_ImmediatePool.Allocate();
|
||||
if(ret != NULL) return ret;
|
||||
|
||||
// fall back to additional pools, if there are any
|
||||
for(size_t i=0; i < m_AdditionalPools.size(); i++)
|
||||
{
|
||||
ret = m_AdditionalPools[i]->Allocate();
|
||||
if(ret != NULL)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// warn when we need to allocate an additional pool
|
||||
#ifdef INCLUDE_TYPE_NAMES
|
||||
RDCWARN("Ran out of free slots in %hs pool!", GetTypeName<WrapType>::Name());
|
||||
#else
|
||||
RDCWARN("Ran out of free slots in pool 0x%p!", &m_ImmediatePool.items[0]);
|
||||
#endif
|
||||
|
||||
// allocate a new additional pool and use that to allocate from
|
||||
m_AdditionalPools.push_back(new ItemPool());
|
||||
|
||||
#ifdef INCLUDE_TYPE_NAMES
|
||||
RDCDEBUG("WrappingPool[%d]<%hs>: %p -> %p", (uint32_t)m_AdditionalPools.size() - 1, GetTypeName<WrapType>::Name(),
|
||||
&m_AdditionalPools.back()->items[0], &m_AdditionalPools.back()->items[AllocCount-1]);
|
||||
#endif
|
||||
|
||||
return m_AdditionalPools.back()->Allocate();
|
||||
}
|
||||
|
||||
bool IsAlloc(void *p)
|
||||
{
|
||||
// we can check the immediate pool without locking
|
||||
if(m_ImmediatePool.IsAlloc(p))
|
||||
return true;
|
||||
|
||||
// if we have additional pools, lock and check them.
|
||||
// TODO: Check for additional pools in a lock-free manner,
|
||||
// to prevent the cost of locking if there are no more pools.
|
||||
{
|
||||
SCOPED_LOCK(m_Lock);
|
||||
|
||||
for(size_t i=0; i < m_AdditionalPools.size(); i++)
|
||||
if(m_AdditionalPools[i]->IsAlloc(p))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Deallocate(void *p)
|
||||
{
|
||||
SCOPED_LOCK(m_Lock);
|
||||
|
||||
// try immediate pool
|
||||
if(m_ImmediatePool.IsAlloc(p))
|
||||
{
|
||||
m_ImmediatePool.Deallocate(p);
|
||||
return;
|
||||
}
|
||||
else if(!m_AdditionalPools.empty())
|
||||
{
|
||||
// fall back and try additional pools
|
||||
for(size_t i=0; i < m_AdditionalPools.size(); i++)
|
||||
{
|
||||
if(m_AdditionalPools[i]->IsAlloc(p))
|
||||
{
|
||||
m_AdditionalPools[i]->Deallocate(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is an error - deleting an object that we don't recognise
|
||||
#ifdef INCLUDE_TYPE_NAMES
|
||||
RDCERR("Resource being deleted through wrong pool - 0x%p not a member of %hs", p, GetTypeName<WrapType>::Name());
|
||||
#else
|
||||
RDCERR("Resource being deleted through wrong pool - 0x%p not a member of 0x%p", p, &m_ImmediatePool.items[0]));
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
WrappingPool()
|
||||
{
|
||||
#ifdef INCLUDE_TYPE_NAMES
|
||||
RDCDEBUG("WrappingPool<%hs>: %p -> %p", GetTypeName<WrapType>::Name(), &m_ImmediatePool.items[0], &m_ImmediatePool.items[AllocCount-1]);
|
||||
#endif
|
||||
|
||||
RDCCOMPILE_ASSERT(PoolCount*AllocByteSize <= MaxPoolByteSize, "Pool is bigger than max pool size cap");
|
||||
RDCCOMPILE_ASSERT(PoolCount > 2, "Pool isn't greater than 2 in size. Bad parameters?"); // make sure parameters are sane
|
||||
}
|
||||
~WrappingPool()
|
||||
{
|
||||
for(size_t i=0; i < m_AdditionalPools.size(); i++)
|
||||
delete m_AdditionalPools[i];
|
||||
|
||||
m_AdditionalPools.clear();
|
||||
}
|
||||
|
||||
static const size_t AllocCount = PoolCount;
|
||||
static const size_t AllocByteSize;
|
||||
|
||||
Threading::CriticalSection m_Lock;
|
||||
|
||||
struct ItemPool
|
||||
{
|
||||
ItemPool()
|
||||
{
|
||||
lastAllocIdx = 0;
|
||||
RDCEraseEl(allocated);
|
||||
|
||||
items = (WrapType *)(new uint8_t[AllocCount*AllocByteSize]);
|
||||
}
|
||||
~ItemPool()
|
||||
{
|
||||
delete[] (uint8_t *)items;
|
||||
}
|
||||
|
||||
void *Allocate()
|
||||
{
|
||||
int lastAlloc = lastAllocIdx;
|
||||
|
||||
if(allocated[lastAlloc])
|
||||
{
|
||||
int end = lastAlloc;
|
||||
|
||||
do
|
||||
{
|
||||
lastAlloc = (lastAlloc+1) % PoolCount;
|
||||
} while (allocated[lastAlloc] && lastAlloc != end);
|
||||
|
||||
if(allocated[lastAlloc])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *ret = (void *)&items[lastAlloc];
|
||||
allocated[lastAlloc] = true;
|
||||
|
||||
#if !defined(RELEASE)
|
||||
memset(ret, 0xb0, AllocByteSize);
|
||||
#endif
|
||||
|
||||
lastAllocIdx = lastAlloc;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Deallocate(void *p)
|
||||
{
|
||||
RDCASSERT(IsAlloc(p));
|
||||
|
||||
#if !defined(RELEASE)
|
||||
if(!IsAlloc(p))
|
||||
{
|
||||
RDCERR("Resource being deleted through wrong pool - 0x%p not a memory of 0x%p", p, &items[0]);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t idx = (WrapType *)p-&items[0];
|
||||
|
||||
allocated[idx] = false;
|
||||
|
||||
#if !defined(RELEASE)
|
||||
memset(p, 0xfe, AllocByteSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsAlloc(void *p)
|
||||
{
|
||||
return p >= &items[0] && p < &items[PoolCount];
|
||||
}
|
||||
|
||||
WrapType *items;
|
||||
|
||||
// could possibly make this uint32s and check via bitmasks, but
|
||||
// we'll see if it shows up in profiling
|
||||
bool allocated[PoolCount];
|
||||
|
||||
// store the last allocations index. Good place to start from and we
|
||||
// go through the pool in a ring. Good performance when the pool is empty
|
||||
// or contiguously allocated, poorer performance when the pool gets filled up.
|
||||
// It also has the bonus of handling repeated new/free well by reallocating the
|
||||
// same element.
|
||||
int lastAllocIdx;
|
||||
};
|
||||
|
||||
ItemPool m_ImmediatePool;
|
||||
std::vector<ItemPool *> m_AdditionalPools;
|
||||
|
||||
friend typename FriendMaker<WrapType>::Type;
|
||||
};
|
||||
|
||||
#define ALLOCATE_WITH_WRAPPED_POOL(...) \
|
||||
typedef WrappingPool<__VA_ARGS__> PoolType; \
|
||||
static PoolType m_Pool; \
|
||||
void* operator new(size_t sz) { return m_Pool.Allocate(); } \
|
||||
void operator delete(void* p) { m_Pool.Deallocate(p); } \
|
||||
static bool IsAlloc(void *p) { return m_Pool.IsAlloc(p); }
|
||||
|
||||
#ifdef INCLUDE_TYPE_NAMES
|
||||
#define DECL_TYPENAME(a) template<> const char *GetTypeName< a >::Name() { return #a; }
|
||||
#else
|
||||
#define DECL_TYPENAME(a)
|
||||
#endif
|
||||
|
||||
#define WRAPPED_POOL_INST(a) \
|
||||
a::PoolType a::m_Pool; \
|
||||
const size_t a::PoolType::AllocByteSize = sizeof(a); \
|
||||
DECL_TYPENAME(a);
|
||||
Reference in New Issue
Block a user