Explorar el Código

Added CrashHandler (untested)

BearishSun hace 10 años
padre
commit
baaa09abee

+ 0 - 10
BansheeCore/Source/BsCoreApplication.cpp

@@ -46,18 +46,10 @@
 #include "BsShader.h"
 #include "BsShader.h"
 #include "BsTechnique.h"
 #include "BsTechnique.h"
 #include "BsPass.h"
 #include "BsPass.h"
-
 #include "BsRendererManager.h"
 #include "BsRendererManager.h"
 
 
-#include <csignal>
-
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	void handleAbort(int error)
-	{
-		BS_EXCEPT(InternalErrorException, "abort() called.");
-	}
-
 	CoreApplication::CoreApplication(START_UP_DESC& desc)
 	CoreApplication::CoreApplication(START_UP_DESC& desc)
 		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), 
 		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), 
 		mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc)
 		mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc)
@@ -117,8 +109,6 @@ namespace BansheeEngine
 
 
 	void CoreApplication::onStartUp()
 	void CoreApplication::onStartUp()
 	{
 	{
-		signal(SIGABRT, handleAbort);
-
 		UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
 		UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
 
 
 		Platform::_startUp();
 		Platform::_startUp();

+ 1 - 13
BansheeD3D9RenderAPI/Source/BsD3D9RenderAPI.cpp

@@ -185,19 +185,7 @@ namespace BansheeEngine
 		String msg;
 		String msg;
 
 
 		mResourceManager->lockDeviceAccess();
 		mResourceManager->lockDeviceAccess();
-
-		try
-		{
-			mDeviceManager->linkRenderWindow(d3d9renderWindow);
-		}
-		catch (const BansheeEngine::RenderingAPIException&)
-		{
-			// after catching the exception, clean up
-			mResourceManager->unlockDeviceAccess();
-
-			// re-throw
-			throw;
-		}
+		mDeviceManager->linkRenderWindow(d3d9renderWindow);
 
 
 		mResourceManager->unlockDeviceAccess();
 		mResourceManager->unlockDeviceAccess();
 	}	
 	}	

+ 14 - 9
BansheeEditorExec/BsEditorExec.cpp

@@ -1,13 +1,13 @@
-#include <windows.h>
 #include <iostream>
 #include <iostream>
 #include <stdio.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <io.h>
 #include <io.h>
-
 #include "BsEditorApplication.h"
 #include "BsEditorApplication.h"
-
-// DEBUG ONLY
 #include "BsDebug.h"
 #include "BsDebug.h"
+#include "BsCrashHandler.h"
+
+#if BS_PLATFORM == BS_PLATFORM_WIN32
+#include <windows.h>
 
 
 using namespace BansheeEngine;
 using namespace BansheeEngine;
 
 
@@ -55,7 +55,7 @@ void ShutdownDebugConsole()
 	DWORD CharsRead;
 	DWORD CharsRead;
 	ReadConsole(ConsoleInput, &InputBuffer, 1, &CharsRead, 0);
 	ReadConsole(ConsoleInput, &InputBuffer, 1, &CharsRead, 0);
 }
 }
-#endif
+#endif // End BS_DEBUG_MODE
 
 
 int CALLBACK WinMain(
 int CALLBACK WinMain(
 	_In_  HINSTANCE hInstance,
 	_In_  HINSTANCE hInstance,
@@ -68,20 +68,25 @@ int CALLBACK WinMain(
 	InitializeDebugConsole();
 	InitializeDebugConsole();
 #endif
 #endif
 
 
-	try
+	CrashHandler::startUp();
+
+	__try
 	{
 	{
 		EditorApplication::startUp(RenderAPIPlugin::DX11);
 		EditorApplication::startUp(RenderAPIPlugin::DX11);
 		EditorApplication::instance().runMainLoop();
 		EditorApplication::instance().runMainLoop();
 		EditorApplication::shutDown();
 		EditorApplication::shutDown();
 	}
 	}
-	catch(Exception& e)
+	__except (gCrashHandler().reportCrash(GetExceptionInformation()))
 	{
 	{
-		LOGERR(e.getFullDescription());
+
 	}
 	}
 
 
 #if BS_DEBUG_MODE
 #if BS_DEBUG_MODE
 	ShutdownDebugConsole();
 	ShutdownDebugConsole();
 #endif
 #endif
 
 
+	CrashHandler::shutDown();
+
 	return 0;
 	return 0;
-}
+}
+#endif // End BS_PLATFORM

+ 4 - 2
BansheeUtility/BansheeUtility.vcxproj

@@ -294,13 +294,15 @@
     <ClCompile Include="Source\BsSphere.cpp" />
     <ClCompile Include="Source\BsSphere.cpp" />
     <ClCompile Include="Source\BsTexAtlasGenerator.cpp" />
     <ClCompile Include="Source\BsTexAtlasGenerator.cpp" />
     <ClCompile Include="Source\ThirdParty\md5.cpp" />
     <ClCompile Include="Source\ThirdParty\md5.cpp" />
-    <ClCompile Include="Source\Win32\BsFileSystem.cpp" />
-    <ClCompile Include="Source\Win32\BsTimer.cpp" />
+    <ClCompile Include="Source\Win32\BsWin32CrashHandler.cpp" />
+    <ClCompile Include="Source\Win32\BsWin32FileSystem.cpp" />
+    <ClCompile Include="Source\Win32\BsWin32Timer.cpp" />
     <ClInclude Include="Include\BsAny.h" />
     <ClInclude Include="Include\BsAny.h" />
     <ClInclude Include="Include\BsBinaryCloner.h" />
     <ClInclude Include="Include\BsBinaryCloner.h" />
     <ClInclude Include="Include\BsBounds.h" />
     <ClInclude Include="Include\BsBounds.h" />
     <ClInclude Include="Include\BsCapsule.h" />
     <ClInclude Include="Include\BsCapsule.h" />
     <ClInclude Include="Include\BsConvexVolume.h" />
     <ClInclude Include="Include\BsConvexVolume.h" />
+    <ClInclude Include="Include\BsCrashHandler.h" />
     <ClInclude Include="Include\BsEvent.h" />
     <ClInclude Include="Include\BsEvent.h" />
     <ClInclude Include="Include\BsLineSegment3.h" />
     <ClInclude Include="Include\BsLineSegment3.h" />
     <ClInclude Include="Include\BsMatrixNxM.h" />
     <ClInclude Include="Include\BsMatrixNxM.h" />

+ 15 - 6
BansheeUtility/BansheeUtility.vcxproj.filters

@@ -51,6 +51,9 @@
     <Filter Include="Header Files\RTTI">
     <Filter Include="Header Files\RTTI">
       <UniqueIdentifier>{57091de5-56e6-4b9a-9b76-8ecaeee60c3f}</UniqueIdentifier>
       <UniqueIdentifier>{57091de5-56e6-4b9a-9b76-8ecaeee60c3f}</UniqueIdentifier>
     </Filter>
     </Filter>
+    <Filter Include="Source Files\Win32">
+      <UniqueIdentifier>{e56d4454-f68c-4190-88cf-98a5cc24f6b4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsThreadPool.h">
     <ClInclude Include="Include\BsThreadPool.h">
@@ -302,6 +305,9 @@
     <ClInclude Include="Include\BsStaticAlloc.h">
     <ClInclude Include="Include\BsStaticAlloc.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsCrashHandler.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsThreadPool.cpp">
     <ClCompile Include="Source\BsThreadPool.cpp">
@@ -310,9 +316,6 @@
     <ClCompile Include="Source\BsTaskScheduler.cpp">
     <ClCompile Include="Source\BsTaskScheduler.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="Source\Win32\BsTimer.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsTime.cpp">
     <ClCompile Include="Source\BsTime.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
@@ -340,9 +343,6 @@
     <ClCompile Include="Source\BsFrameAlloc.cpp">
     <ClCompile Include="Source\BsFrameAlloc.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="Source\Win32\BsFileSystem.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsException.cpp">
     <ClCompile Include="Source\BsException.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
@@ -481,5 +481,14 @@
     <ClCompile Include="Source\BsGlobalFrameAlloc.cpp">
     <ClCompile Include="Source\BsGlobalFrameAlloc.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\Win32\BsWin32FileSystem.cpp">
+      <Filter>Source Files\Win32</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\Win32\BsWin32CrashHandler.cpp">
+      <Filter>Source Files\Win32</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\Win32\BsWin32Timer.cpp">
+      <Filter>Source Files\Win32</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 73 - 0
BansheeUtility/Include/BsCrashHandler.h

@@ -0,0 +1,73 @@
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsModule.h"
+
+#if BS_PLATFORM == BS_PLATFORM_WIN32
+#include "windows.h"
+#endif
+
+#define BS_MAX_STACKTRACE_DEPTH 200
+#define BS_MAX_STACKTRACE_NAME_BYTES 1024
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Saves crash data and notifies the user when a crash occurs.
+	 */
+	// TODO - Crashes are reported in the same process as the main application. This can be a problem if the crash was caused
+	// by heap. Any further use of the heap by the reporting methods will cause a silent crash, failing to log it. A more appropriate
+	// way of doing it should be to resume another process to actually handle the crash.
+	class BS_UTILITY_EXPORT CrashHandler : public Module<CrashHandler>
+	{
+	public:
+		CrashHandler();
+		~CrashHandler();
+
+		/**
+		 * @brief	Records a crash with a custom error message.
+		 * 			
+		 * @param	type		Type of the crash that occurred. e.g. "InvalidParameter".
+		 * @param	description	More detailed description of the issue that caused the crash.
+		 * @param	function	Optional name of the function where the error occurred.
+		 * @param	file		Optional name of the source code file in which the code that crashed the program exists.
+		 * @param	line		Optional source code line at which the crash was triggered at.
+		 */
+		void reportCrash(const char* type, const char* description, const char* function = nullptr, const char* file = nullptr, UINT32 line = 0);
+
+#if BS_PLATFORM == BS_PLATFORM_WIN32
+		/**
+		 * @brief	Records a crash resulting from a Windows-specific SEH exception. 
+		 * 			
+		 * @param	exceptionData	Exception data returned from GetExceptionInformation()
+		 * 							
+		 * @returns	Code that signals the __except exception handler on how to proceed.
+		 */
+		int reportCrash(EXCEPTION_POINTERS* exceptionData);
+#endif
+
+		/**
+		 * @brief	Returns a string containing a current stack trace. If function can be found in the symbol
+		 * 			table its readable name will be present in the stack trace, otherwise just its address.
+		 * 						
+		 * @returns	String containing the call stack with each function on its own line.
+		 */
+		String getStackTrace();
+	private:
+		/**
+		 * @brief	Returns path to the folder into which to store the crash reports.
+		 */
+		Path getCrashFolder();
+
+		static const wchar_t* CrashReportFolder;
+		static const wchar_t* CrashLogName;
+
+		struct Data;
+		Data* m;
+	};
+
+	/**
+	 * @brief	Returns an instance of the CrashHandler.
+	 */
+	BS_UTILITY_EXPORT CrashHandler& gCrashHandler();
+}

+ 4 - 3
BansheeUtility/Include/BsDynLib.h

@@ -32,8 +32,11 @@ namespace BansheeEngine
 	 */
 	 */
 	class BS_UTILITY_EXPORT DynLib
 	class BS_UTILITY_EXPORT DynLib
     {
     {
-
     public:
     public:
+		/**
+		 * @brief	Constructs the dynamic library object and loads the library with the specified name.
+		 */
+		DynLib(const String& name);
         ~DynLib();
         ~DynLib();
 
 
 		/** 
 		/** 
@@ -64,8 +67,6 @@ namespace BansheeEngine
 	protected:
 	protected:
 		friend class DynLibManager;
 		friend class DynLibManager;
 
 
-		DynLib(const String& name);
-
 		/** 
 		/** 
 		 * @brief	Gets the last loading error.
 		 * @brief	Gets the last loading error.
 		 */
 		 */

+ 1 - 1
BansheeUtility/Include/BsLog.h

@@ -50,7 +50,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Saves the log file to disk.
 		 * @brief	Saves the log file to disk.
 		 */
 		 */
-		void saveToFile(const WString& path);
+		void saveToFile(const Path& path);
 
 
 	private:
 	private:
 		Vector<LogEntry*> mEntries;
 		Vector<LogEntry*> mEntries;

+ 57 - 3
BansheeUtility/Include/BsTimer.h

@@ -2,6 +2,60 @@
 
 
 #include "BsPrerequisitesUtil.h"
 #include "BsPrerequisitesUtil.h"
 
 
-#if BS_PLATFORM == BS_PLATFORM_WIN32
-#include "Win32/BsTimerImp.h"
-#endif
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Timer class used for querying high precision timers.
+	 *
+	 * @note	Not thread safe.
+	 */
+	class BS_UTILITY_EXPORT Timer
+    {
+    public:
+		/**
+		 * @brief	Construct the timer and start timing.
+		 */
+		Timer();
+		~Timer();
+
+		/**
+		 * @brief	Reset the timer to zero.
+		 */
+		void reset();
+
+		/**
+		 * @brief	Returns time in milliseconds since timer was initialized or
+		 * 			last reset.
+		 */
+		unsigned long getMilliseconds();
+
+		/**
+		 * @brief	Returns time in microseconds since timer was initialized or
+		 * 			last reset.
+		 */
+		unsigned long getMicroseconds();
+
+		/**
+		 * @brief	Returns time in milliseconds since timer was initialized or
+		 * 			last reset. Only CPU timer measured.
+		 */
+		unsigned long getMillisecondsCPU();
+
+		/**
+		 * @brief	Returns time in microseconds since timer was initialized or
+		 * 			last reset. Only CPU timer measured.
+		 */
+		unsigned long getMicrosecondsCPU();
+
+		/**
+		 * @brief	Returns the time at which the timer was initialized, in milliseconds.
+		 *
+		 * @return	Time in milliseconds.
+		 */
+		unsigned long getStartMs() const;
+
+	private:
+		struct Data;
+		Data* m;
+    };
+}

+ 0 - 71
BansheeUtility/Include/Win32/BsTimerImp.h

@@ -1,71 +0,0 @@
-#pragma once
-
-#include "../BsPrerequisitesUtil.h"
-
-#ifndef WIN32_LEAN_AND_MEAN
-#	define WIN32_LEAN_AND_MEAN
-#endif
-#if !defined(NOMINMAX) && defined(_MSC_VER)
-#	define NOMINMAX // Required to stop windows.h messing up std::min
-#endif
-#include "windows.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Timer class used for querying high precision timers.
-	 *
-	 * @note	Not thread safe.
-	 */
-	class BS_UTILITY_EXPORT Timer
-    {
-    public:
-		/**
-		 * @brief	Construct the timer and start timing.
-		 */
-		Timer();
-		~Timer();
-
-		/**
-		 * @brief	Reset the timer to zero.
-		 */
-		void reset();
-
-		/**
-		 * @brief	Returns time in milliseconds since timer was initialized or
-		 * 			last reset.
-		 */
-		unsigned long getMilliseconds();
-
-		/**
-		 * @brief	Returns time in microseconds since timer was initialized or
-		 * 			last reset.
-		 */
-		unsigned long getMicroseconds();
-
-		/**
-		 * @brief	Returns time in milliseconds since timer was initialized or
-		 * 			last reset. Only CPU timer measured.
-		 */
-		unsigned long getMillisecondsCPU();
-
-		/**
-		 * @brief	Returns time in microseconds since timer was initialized or
-		 * 			last reset. Only CPU timer measured.
-		 */
-		unsigned long getMicrosecondsCPU();
-
-		/**
-		 * @brief	Returns the time at which the timer was initialized, in milliseconds.
-		 *
-		 * @return	Time in milliseconds.
-		 */
-		unsigned long getStartMs() const;
-
-	private:
-		clock_t mZeroClock;
-
-		LARGE_INTEGER mStartTime;
-		LARGE_INTEGER mFrequency;
-    };
-}

+ 0 - 69
BansheeUtility/Include/Win32/CmTimerImp.h

@@ -1,69 +0,0 @@
-#pragma once
-
-#include "../BsPrerequisitesUtil.h"
-
-#ifndef WIN32_LEAN_AND_MEAN
-#	define WIN32_LEAN_AND_MEAN
-#endif
-#if !defined(NOMINMAX) && defined(_MSC_VER)
-#	define NOMINMAX // Required to stop windows.h messing up std::min
-#endif
-#include "windows.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Timer class used for querying high precision timers.
-	 */
-	class BS_UTILITY_EXPORT Timer
-    {
-    public:
-		/**
-		 * @brief	Construct the timer and start timing.
-		 */
-		Timer();
-		~Timer();
-
-		/**
-		 * @brief	Reset the timer to zero.
-		 */
-		void reset();
-
-		/**
-		 * @brief	Returns time in milliseconds since timer was initialized or
-		 * 			last reset.
-		 */
-		unsigned long getMilliseconds();
-
-		/**
-		 * @brief	Returns time in microseconds since timer was initialized or
-		 * 			last reset.
-		 */
-		unsigned long getMicroseconds();
-
-		/**
-		 * @brief	Returns time in milliseconds since timer was initialized or
-		 * 			last reset. Only CPU timer measured.
-		 */
-		unsigned long getMillisecondsCPU();
-
-		/**
-		 * @brief	Returns time in microseconds since timer was initialized or
-		 * 			last reset. Only CPU timer measured.
-		 */
-		unsigned long getMicrosecondsCPU();
-
-		/**
-		 * @brief	Returns the time at which the timer was initialized, in milliseconds.
-		 *
-		 * @return	Time in milliseconds.
-		 */
-		unsigned long getStartMs() const;
-
-	private:
-		clock_t mZeroClock;
-
-		LARGE_INTEGER mStartTime;
-		LARGE_INTEGER mFrequency;
-    };
-}

+ 3 - 1
BansheeUtility/Source/BsDynLib.cpp

@@ -19,7 +19,9 @@ namespace BansheeEngine
     DynLib::DynLib(const String& name)
     DynLib::DynLib(const String& name)
     {
     {
         mName = name;
         mName = name;
-        m_hInst = NULL;
+        m_hInst = nullptr;
+
+		load();
     }
     }
 
 
     DynLib::~DynLib()
     DynLib::~DynLib()

+ 1 - 3
BansheeUtility/Source/BsDynLibManager.cpp

@@ -7,7 +7,7 @@ namespace BansheeEngine
 	{
 	{
 	}
 	}
 
 
-    DynLib* DynLibManager::load( const String& filename)
+    DynLib* DynLibManager::load(const String& filename)
     {
     {
 		auto iterFind = mLoadedLibraries.find(filename);
 		auto iterFind = mLoadedLibraries.find(filename);
 		if (iterFind != mLoadedLibraries.end())
 		if (iterFind != mLoadedLibraries.end())
@@ -17,8 +17,6 @@ namespace BansheeEngine
 		else
 		else
 		{
 		{
 	        DynLib* newLib = new (bs_alloc<DynLib>()) DynLib(filename);
 	        DynLib* newLib = new (bs_alloc<DynLib>()) DynLib(filename);
-
-			newLib->load();       
         	mLoadedLibraries[filename] = newLib;
         	mLoadedLibraries[filename] = newLib;
 
 
 	        return newLib;
 	        return newLib;

+ 1 - 1
BansheeUtility/Source/BsLog.cpp

@@ -39,7 +39,7 @@ namespace BansheeEngine
 		mEntries.clear();
 		mEntries.clear();
 	}
 	}
 
 
-	void Log::saveToFile(const WString& path)
+	void Log::saveToFile(const Path& path)
 	{
 	{
 		// TODO - Save the log as HTML
 		// TODO - Save the log as HTML
 		BS_EXCEPT(NotImplementedException, "Log save to file not yet implemented.");
 		BS_EXCEPT(NotImplementedException, "Log save to file not yet implemented.");

+ 0 - 68
BansheeUtility/Source/Win32/BsTimer.cpp

@@ -1,68 +0,0 @@
-#include "BsTimer.h"
-#include "BsBitwise.h"
-
-namespace BansheeEngine
-{
-	Timer::Timer()
-	{
-		reset();
-	}
-
-	Timer::~Timer()
-	{
-	}
-
-	void Timer::reset()
-	{
-		QueryPerformanceFrequency(&mFrequency);
-		QueryPerformanceCounter(&mStartTime);
-
-		mZeroClock = clock();
-	}
-
-	unsigned long Timer::getMilliseconds()
-	{
-		LARGE_INTEGER curTime;
-		QueryPerformanceCounter(&curTime);
-
-		LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
-    
-		// Scale by 1000 for milliseconds
-		unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
-
-		return newTicks;
-	}
-
-	unsigned long Timer::getStartMs() const
-	{
-		unsigned long newTicks = (unsigned long) (1000 * mStartTime.QuadPart / mFrequency.QuadPart);
-
-		return newTicks;
-	}
-
-	unsigned long Timer::getMicroseconds()
-	{
-		LARGE_INTEGER curTime;
-		QueryPerformanceCounter(&curTime);
-
-		LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
-    
-		// Scale by 1000000 for microseconds
-		unsigned long newMicro = (unsigned long) (1000000 * newTime / mFrequency.QuadPart);
-
-		return newMicro;
-	}
-
-	unsigned long Timer::getMillisecondsCPU()
-	{
-		clock_t newClock = clock();
-		return (unsigned long)((float)(newClock - mZeroClock) / ((float)CLOCKS_PER_SEC / 1000.0f));
-	}
-
-
-	unsigned long Timer::getMicrosecondsCPU()
-	{
-		clock_t newClock = clock();
-		return (unsigned long)((float)(newClock - mZeroClock) / ((float)CLOCKS_PER_SEC / 1000000.0f));
-	}
-}

+ 484 - 0
BansheeUtility/Source/Win32/BsWin32CrashHandler.cpp

@@ -0,0 +1,484 @@
+#include "BsCrashHandler.h"
+#include "BsDebug.h"
+#include "BsDynLib.h"
+#include "BsFileSystem.h"
+#include "DbgHelp.h"
+#include <psapi.h>
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Returns the raw stack trace using the provided context. Raw stack trace contains only
+	 * 			function addresses.
+	 * 			
+	 * @param	context		Processor context from which to start the stack trace. 
+	 * @param	stackTrace	Output parameter that will contain the function addresses. First address is the deepest
+	 * 						called function and following address is its caller and so on.
+	 * 						
+	 * @returns	Number of functions in the call stack.
+	 */
+	UINT32 win32_getRawStackTrace(CONTEXT context, UINT64 stackTrace[BS_MAX_STACKTRACE_DEPTH])
+	{
+		HANDLE hProcess = GetCurrentProcess();
+		HANDLE hThread = GetCurrentThread();
+		UINT32 machineType;
+
+		STACKFRAME64 stackFrame;
+		memset(&stackFrame, 0, sizeof(stackFrame));
+
+		stackFrame.AddrPC.Mode = AddrModeFlat;
+		stackFrame.AddrStack.Mode = AddrModeFlat;
+		stackFrame.AddrFrame.Mode = AddrModeFlat;
+
+#if BS_ARCH_TYPE == BS_ARCHITECTURE_x86_64
+		stackFrame.AddrPC.Offset = context.Rip;
+		stackFrame.AddrStack.Offset = context.Rsp;
+		stackFrame.AddrFrame.Offset = context.Rbp;
+
+		machineType = IMAGE_FILE_MACHINE_AMD64;
+#else
+		stackFrame.AddrPC.Offset = context.Eip;
+		stackFrame.AddrStack.Offset = context.Esp;
+		stackFrame.AddrFrame.Offset = context.Ebp;
+
+		machineType = IMAGE_FILE_MACHINE_I386;
+#endif
+
+		UINT32 numEntries = 0;
+		while (true)
+		{
+			if (!StackWalk64(machineType, hProcess, hThread, &stackFrame, &context, nullptr,
+				SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
+			{
+				LOGERR("Stack walk failed.");
+				break;
+			}
+
+			if (numEntries < BS_MAX_STACKTRACE_DEPTH)
+				stackTrace[numEntries] = stackFrame.AddrPC.Offset;
+
+			numEntries++;
+
+			if (stackFrame.AddrPC.Offset == 0 || stackFrame.AddrFrame.Offset == 0)
+				break;
+		}
+
+		return numEntries;
+	}
+
+	/**
+	 * @brief	Returns a string containing a stack trace using the provided context. If function can be found in the symbol
+	 * 			table its readable name will be present in the stack trace, otherwise just its address.
+	 * 			
+	 * @param	context		Processor context from which to start the stack trace. 
+	 * @param	skip		Number of bottom-most call stack entries to skip.
+	 * 						
+	 * @returns	String containing the call stack with each function on its own line.
+	 */
+	String win32_getStackTrace(CONTEXT context, int skip = 0)
+	{
+		UINT64 rawStackTrace[BS_MAX_STACKTRACE_DEPTH];
+		UINT32 numEntries = win32_getRawStackTrace(context, rawStackTrace);
+
+		numEntries = std::min((UINT32)BS_MAX_STACKTRACE_DEPTH, numEntries);
+
+		UINT32 bufferSize = sizeof(PIMAGEHLP_SYMBOL64) + BS_MAX_STACKTRACE_NAME_BYTES;
+		UINT8* buffer = (UINT8*)bs_alloc(bufferSize);
+
+		PIMAGEHLP_SYMBOL64 symbol = (PIMAGEHLP_SYMBOL64)buffer;
+		symbol->SizeOfStruct = bufferSize;
+		symbol->MaxNameLength = BS_MAX_STACKTRACE_NAME_BYTES;
+
+		HANDLE hProcess = GetCurrentProcess();
+
+		StringStream outputStream;
+		for (UINT32 i = skip; i < numEntries; i++)
+		{
+			if (i > skip)
+				outputStream << std::endl;
+
+			DWORD64 funcAddress = rawStackTrace[i];
+
+			// Output function name
+			DWORD64 dummy;
+			if (SymGetSymFromAddr64(hProcess, funcAddress, &dummy, symbol))
+				outputStream << StringUtil::format("{0}() - ", symbol->Name);
+
+			// Output file name and line
+			IMAGEHLP_LINE64	lineData;
+			lineData.SizeOfStruct = sizeof(lineData);
+
+			String addressString = toString(funcAddress, 0, ' ', std::ios::hex);
+
+			DWORD column;
+			if (SymGetLineFromAddr64(hProcess, funcAddress, &column, &lineData))
+			{
+				outputStream << StringUtil::format("0x{0} File[{1}:{2} ({3})]", addressString, 
+					lineData.FileName, lineData.LineNumber, column);
+			}
+			else
+			{
+				outputStream << StringUtil::format("0x{0}", addressString);
+			}
+
+			// Output module name
+			IMAGEHLP_MODULE64 moduleData;
+			moduleData.SizeOfStruct = sizeof(moduleData);
+
+			if (SymGetModuleInfo64(hProcess, funcAddress, &moduleData))
+				outputStream << StringUtil::format(" Module[{0}]", moduleData.ImageName);
+		}
+
+		bs_free(buffer);
+
+		return outputStream.str();
+	}
+
+	typedef bool(WINAPI *EnumProcessModulesType)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
+	typedef DWORD(WINAPI *GetModuleBaseNameType)(HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize);
+	typedef DWORD(WINAPI *GetModuleFileNameExType)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize);
+	typedef bool(WINAPI *GetModuleInformationType)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb);
+
+	static DynLib* gPSAPILib = nullptr;
+
+	static EnumProcessModulesType gEnumProcessModules;
+	static GetModuleBaseNameType gGetModuleBaseName;
+	static GetModuleFileNameExType gGetModuleFileNameEx;
+	static GetModuleInformationType gGetModuleInformation;
+
+	/**
+	 * @brief	Dynamically load the PSAPI.dll and the required symbols, if not already loaded.
+	 */
+	void win32_initPSAPI()
+	{
+		if (gPSAPILib != nullptr)
+			return;
+
+		gPSAPILib = bs_new<DynLib>("PSAPI.dll");
+		gEnumProcessModules = (EnumProcessModulesType)gPSAPILib->getSymbol("EnumProcessModules");
+		gGetModuleBaseName = (GetModuleBaseNameType)gPSAPILib->getSymbol("GetModuleFileNameExA");
+		gGetModuleFileNameEx = (GetModuleFileNameExType)gPSAPILib->getSymbol("GetModuleBaseNameA");
+		gGetModuleInformation = (GetModuleInformationType)gPSAPILib->getSymbol("GetModuleInformation");
+	}
+
+	/**
+	 * @brief	Unloads the PSAPI.dll if is loaded.
+	 */
+	void win32_unloadPSAPI()
+	{
+		if (gPSAPILib == nullptr)
+			return;
+
+		gPSAPILib->unload();
+		bs_delete(gPSAPILib);
+		gPSAPILib = nullptr;
+	}
+
+	static bool gSymbolsLoaded = false;
+
+	/**
+	 * @brief	Loads symbols for all modules in the current process. Loaded symbols allow the stack walker to retrieve
+	 * 			human readable method, file, module names and other information.
+	 */
+	void win32_loadSymbols()
+	{
+		if (gSymbolsLoaded)
+			return;
+
+		HANDLE hProcess = GetCurrentProcess();
+		UINT32 options = SymGetOptions();
+
+		options |= SYMOPT_LOAD_LINES;
+		options |= SYMOPT_EXACT_SYMBOLS;
+		options |= SYMOPT_UNDNAME;
+		options |= SYMOPT_FAIL_CRITICAL_ERRORS;
+		options |= SYMOPT_NO_PROMPTS;
+		options |= SYMOPT_DEFERRED_LOADS;
+
+		SymSetOptions(options);
+		SymInitialize(hProcess, nullptr, true);
+
+		DWORD bufferSize;
+		gEnumProcessModules(hProcess, nullptr, 0, &bufferSize);
+
+		HMODULE* modules = (HMODULE*)bs_alloc(bufferSize);
+		gEnumProcessModules(hProcess, modules, bufferSize, &bufferSize);
+
+		UINT32 numModules = bufferSize / sizeof(HMODULE);
+		for (UINT32 i = 0; i < numModules; i++)
+		{
+			MODULEINFO moduleInfo;
+
+			char moduleName[BS_MAX_STACKTRACE_NAME_BYTES];
+			char imageName[BS_MAX_STACKTRACE_NAME_BYTES];
+
+			gGetModuleInformation(hProcess, modules[i], &moduleInfo, sizeof(moduleInfo));
+			gGetModuleFileNameEx(hProcess, modules[i], imageName, BS_MAX_STACKTRACE_NAME_BYTES);
+			gGetModuleBaseName(hProcess, modules[i], moduleName, BS_MAX_STACKTRACE_NAME_BYTES);
+
+			char pdbSearchPath[BS_MAX_STACKTRACE_NAME_BYTES];
+			GetFullPathNameA(imageName, BS_MAX_STACKTRACE_NAME_BYTES, pdbSearchPath, nullptr);
+			SymSetSearchPath(GetCurrentProcess(), pdbSearchPath);
+
+			SymLoadModule64(hProcess, modules[i], imageName, moduleName, (DWORD64)moduleInfo.lpBaseOfDll,
+				(DWORD)moduleInfo.SizeOfImage);
+		}
+
+		bs_free(modules);
+		gSymbolsLoaded = true;
+	}
+
+	/**
+	 * @brief	Converts an exception record into a human readable error message.
+	 */
+	String win32_getExceptionMessage(EXCEPTION_RECORD* record)
+	{
+		String exceptionAddress = toString((UINT64)record->ExceptionAddress, 0, ' ', std::ios::hex);
+
+		String format;
+		switch (record->ExceptionCode)
+		{
+		case EXCEPTION_ACCESS_VIOLATION:
+			{
+				DWORD_PTR violatedAddress = 0;
+				if (record->NumberParameters == 2)
+				{
+					if (record->ExceptionInformation[0] == 0)
+						format = "Unhandled exception at 0x{0}. Access violation reading 0x{1}.";
+					else if (record->ExceptionInformation[0] == 8)
+						format = "Unhandled exception at 0x{0}. Access violation DEP 0x{1}.";
+					else
+						format = "Unhandled exception at 0x{0}. Access violation writing 0x{1}.";
+
+					violatedAddress = record->ExceptionInformation[1];
+				}
+				else
+					format = "Unhandled exception at 0x{0}. Access violation.";
+
+				String violatedAddressStr = toString(violatedAddress, 0, ' ', std::ios::hex);
+				return StringUtil::format(format, exceptionAddress, violatedAddressStr);
+			}
+		case EXCEPTION_IN_PAGE_ERROR:
+		{
+			DWORD_PTR violatedAddress = 0;
+			DWORD_PTR code = 0;
+			if (record->NumberParameters == 3)
+			{
+				if (record->ExceptionInformation[0] == 0)
+					format = "Unhandled exception at 0x{0}. Page fault reading 0x{1} with code 0x{2}.";
+				else if (record->ExceptionInformation[0] == 8)
+					format = "Unhandled exception at 0x{0}. Page fault DEP 0x{1} with code 0x{2}.";
+				else
+					format = "Unhandled exception at 0x{0}. Page fault writing 0x{1} with code 0x{2}.";
+
+				violatedAddress = record->ExceptionInformation[1];
+				code = record->ExceptionInformation[3];
+			}
+			else
+				format = "Unhandled exception at 0x{0}. Page fault.";
+
+			String violatedAddressStr = toString(violatedAddress, 0, ' ', std::ios::hex);
+			String codeStr = toString(code, 0, ' ', std::ios::hex);
+			return StringUtil::format(format, exceptionAddress, violatedAddressStr, codeStr);
+		}
+		case STATUS_ARRAY_BOUNDS_EXCEEDED:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to access an out of range array element.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_DATATYPE_MISALIGNMENT:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to access missaligned data.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_DENORMAL_OPERAND:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point operand too small.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point operation attempted to divide by zero.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_INVALID_OPERATION:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point invalid operation.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_OVERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point overflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_UNDERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point underflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_STACK_CHECK:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point stack overflow/underflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_ILLEGAL_INSTRUCTION:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to execute an illegal instruction.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_PRIV_INSTRUCTION:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to execute a private instruction.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_INT_DIVIDE_BY_ZERO:
+		{
+			format = "Unhandled exception at 0x{0}. Integer operation attempted to divide by zero.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_INT_OVERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Integer operation result has overflown.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_STACK_OVERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Stack overflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		default:
+		{
+			format = "Unhandled exception at 0x{0}. Code 0x{1}.";
+
+			String exceptionCode = toString((UINT32)record->ExceptionCode, 0, ' ', std::ios::hex);
+			return StringUtil::format(format, exceptionAddress, exceptionCode);
+		}
+		}
+	}
+
+	void win32_writeMiniDump(const Path& filePath, EXCEPTION_POINTERS* exceptionData)
+	{
+		HANDLE hFile = CreateFileW(filePath.toWString().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 
+			FILE_ATTRIBUTE_NORMAL, nullptr);
+
+		if (hFile != INVALID_HANDLE_VALUE)
+		{
+			MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
+
+			DumpExceptionInfo.ThreadId = GetCurrentThreadId();
+			DumpExceptionInfo.ExceptionPointers = exceptionData;
+			DumpExceptionInfo.ClientPointers = false;
+
+			MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, 
+				&DumpExceptionInfo, nullptr, nullptr);
+			CloseHandle(hFile);
+		}
+	}
+
+	static const wchar_t* gMiniDumpName = L"minidump.dmp";
+	const wchar_t* CrashHandler::CrashReportFolder = L"CrashReport-{0}/";
+	const wchar_t* CrashHandler::CrashLogName = L"log.html";
+
+	struct CrashHandler::Data
+	{
+		Mutex mutex;
+	};
+
+	CrashHandler::CrashHandler()
+	{
+		m = bs_new<Data>();
+	}
+
+	CrashHandler::~CrashHandler()
+	{
+		win32_unloadPSAPI();
+
+		bs_delete(m);
+	}
+
+	void CrashHandler::reportCrash(const char* type, const char* description, const char* function,
+		const char* file, UINT32 line)
+	{
+		// Win32 debug methods are not thread safe
+		Lock<>(m->mutex);
+
+		String stackTrace = getStackTrace();
+
+		StringStream errorMessageStream;
+		errorMessageStream << "Fatal error occurred in Banshee Engine and the program has to terminate!" << std::endl;
+		errorMessageStream << "\t\t" << type << " - " << description << std::endl;
+		errorMessageStream << "\t\t in " << function << " [" << file << ":" << line << "]" << std::endl;
+		errorMessageStream << std::endl;
+		errorMessageStream << "Stack trace: " << std::endl;
+		errorMessageStream << stackTrace;
+
+		String errorMessage = errorMessageStream.str();
+		gDebug().logError(errorMessage);
+
+		Path crashFolder = getCrashFolder();
+		FileSystem::createDir(crashFolder);
+
+		gDebug().getLog().saveToFile(crashFolder + toWString(CrashLogName));
+		win32_writeMiniDump(crashFolder + toWString(gMiniDumpName), nullptr);
+
+		MessageBoxA(nullptr, errorMessage.c_str(), "Banshee fatal error!", MB_OK);
+
+		// Note: Potentially also log Windows Error Report and/or send crash data to server
+	}
+
+	int CrashHandler::reportCrash(EXCEPTION_POINTERS* exceptionData)
+	{
+		// Win32 debug methods are not thread safe
+		Lock<>(m->mutex);
+
+		win32_initPSAPI();
+		win32_loadSymbols();
+		String stackTrace = win32_getStackTrace(*exceptionData->ContextRecord, 0);
+
+		StringStream errorMessageStream;
+		errorMessageStream << "Fatal error occurred in Banshee Engine and the program has to terminate!" << std::endl;
+		errorMessageStream << "\t\t" << win32_getExceptionMessage(exceptionData->ExceptionRecord);
+		errorMessageStream << std::endl;
+		errorMessageStream << "Stack trace: " << std::endl;
+		errorMessageStream << stackTrace;
+
+		String errorMessage = errorMessageStream.str();
+		gDebug().logError(errorMessage);
+
+		Path crashFolder = getCrashFolder();
+		FileSystem::createDir(crashFolder);
+
+		gDebug().getLog().saveToFile(crashFolder + toWString(CrashLogName));
+		win32_writeMiniDump(crashFolder + toWString(gMiniDumpName), exceptionData);
+
+		MessageBoxA(nullptr, errorMessage.c_str(), "Banshee fatal error!", MB_OK);
+
+		// Note: Potentially also log Windows Error Report and/or send crash data to server
+
+		return EXCEPTION_EXECUTE_HANDLER;
+	}
+
+	Path CrashHandler::getCrashFolder()
+	{
+		SYSTEMTIME systemTime;
+		GetLocalTime(&systemTime);
+
+		WString timeStamp = L"{0}-{1}-{2}_{3}:{4}";
+		timeStamp = StringUtil::format(timeStamp, systemTime.wYear, systemTime.wMonth, systemTime.wDay, 
+			systemTime.wHour, systemTime.wMinute);
+
+		WString folderName = StringUtil::format(CrashReportFolder, timeStamp);
+
+		return FileSystem::getWorkingDirectoryPath() + folderName;
+	}
+
+	String CrashHandler::getStackTrace()
+	{
+		CONTEXT context;
+		RtlCaptureContext(&context);
+
+		win32_initPSAPI();
+		win32_loadSymbols();
+		return win32_getStackTrace(context, 0);
+	}
+}

+ 0 - 0
BansheeUtility/Source/Win32/BsFileSystem.cpp → BansheeUtility/Source/Win32/BsWin32FileSystem.cpp


+ 86 - 0
BansheeUtility/Source/Win32/BsWin32Timer.cpp

@@ -0,0 +1,86 @@
+#include "BsTimer.h"
+#include "BsBitwise.h"
+
+#ifndef WIN32_LEAN_AND_MEAN
+#	define WIN32_LEAN_AND_MEAN
+#endif
+#if !defined(NOMINMAX) && defined(_MSC_VER)
+#	define NOMINMAX // Required to stop windows.h messing up std::min
+#endif
+#include "windows.h"
+
+namespace BansheeEngine
+{
+	struct Timer::Data
+	{
+		clock_t zeroClock;
+
+		LARGE_INTEGER startTime;
+		LARGE_INTEGER frequency;
+	};
+
+	Timer::Timer()
+	{
+		m = bs_new<Data>();
+		reset();
+	}
+
+	Timer::~Timer()
+	{
+		bs_delete(m);
+	}
+
+	void Timer::reset()
+	{
+		QueryPerformanceFrequency(&m->frequency);
+		QueryPerformanceCounter(&m->startTime);
+
+		m->zeroClock = clock();
+	}
+
+	unsigned long Timer::getMilliseconds()
+	{
+		LARGE_INTEGER curTime;
+		QueryPerformanceCounter(&curTime);
+
+		LONGLONG newTime = curTime.QuadPart - m->startTime.QuadPart;
+    
+		// Scale by 1000 for milliseconds
+		unsigned long newTicks = (unsigned long)(1000 * newTime / m->frequency.QuadPart);
+
+		return newTicks;
+	}
+
+	unsigned long Timer::getStartMs() const
+	{
+		unsigned long newTicks = (unsigned long)(1000 * m->startTime.QuadPart / m->frequency.QuadPart);
+
+		return newTicks;
+	}
+
+	unsigned long Timer::getMicroseconds()
+	{
+		LARGE_INTEGER curTime;
+		QueryPerformanceCounter(&curTime);
+
+		LONGLONG newTime = curTime.QuadPart - m->startTime.QuadPart;
+    
+		// Scale by 1000000 for microseconds
+		unsigned long newMicro = (unsigned long)(1000000 * newTime / m->frequency.QuadPart);
+
+		return newMicro;
+	}
+
+	unsigned long Timer::getMillisecondsCPU()
+	{
+		clock_t newClock = clock();
+		return (unsigned long)((float)(newClock - m->zeroClock) / ((float)CLOCKS_PER_SEC / 1000.0f));
+	}
+
+
+	unsigned long Timer::getMicrosecondsCPU()
+	{
+		clock_t newClock = clock();
+		return (unsigned long)((float)(newClock - m->zeroClock) / ((float)CLOCKS_PER_SEC / 1000000.0f));
+	}
+}

+ 11 - 0
RenderBeast/Include/BsRenderBeast.h

@@ -226,6 +226,17 @@ namespace BansheeEngine
 		 */
 		 */
 		void refreshSamplerOverrides(bool force = false);
 		void refreshSamplerOverrides(bool force = false);
 
 
+		/**
+		 * @brief	Extracts the necessary values from the projection matrix that allow you to transform
+		 * 			device Z value into world Z value.
+		 * 			
+		 * @param	projMatrix	Projection matrix that was used to create the device Z value to transform.
+		 * 						
+		 * @returns	Returns two values that can be used to transform device z to world z using this formula:
+		 * 			z = 1 / (deviceZ * x - y)
+		 */
+		static Vector2 getDeviceZTransform(const Matrix4& projMatrix);
+
 		/**
 		/**
 		 * @brief	Activates the specified pass on the pipeline.
 		 * @brief	Activates the specified pass on the pipeline.
 		 *
 		 *

+ 9 - 0
RenderBeast/Source/BsRenderBeast.cpp

@@ -741,6 +741,15 @@ namespace BansheeEngine
 		cameraData.transparentQueue->sort();
 		cameraData.transparentQueue->sort();
 	}
 	}
 
 
+	Vector2 RenderBeast::getDeviceZTransform(const Matrix4& projMatrix)
+	{
+		Vector2 output;
+		output.x = 1.0f / projMatrix[2][2];
+		output.y = projMatrix[2][3] / projMatrix[2][2];
+
+		return output;
+	}
+
 	void RenderBeast::refreshSamplerOverrides(bool force)
 	void RenderBeast::refreshSamplerOverrides(bool force)
 	{
 	{
 		for (auto& entry : mSamplerOverrides)
 		for (auto& entry : mSamplerOverrides)

+ 12 - 25
TODOExperimentation.txt

@@ -7,33 +7,20 @@ Determine how is light bleeding handled (if at all)
 ---------------------- IMPLEMENTATION ---------------------------
 ---------------------- IMPLEMENTATION ---------------------------
 
 
 Next week:
 Next week:
- - Store render targets per camera (create and update them as needed)
- - Create shaders that write to gbuffer (DX11/OpenGL only)
- - Create shaders that render lights for deferred rendering
+ - Finish up DefferedPointLightPass by generating cone geometry in shader
+ - Ensure all shaders compile
+ - Generate C++ code for populating cbuffers for deferred shaders (2+ days)
+ - Modify Light so it generated adequate number of vertices required for cone geometry, without actually creating the cone
  - Think about how to handle post-processing shaders (HDR tone mapping)
  - Think about how to handle post-processing shaders (HDR tone mapping)
  - Add cube and 3D support for render texture pool
  - Add cube and 3D support for render texture pool
+ - Load up and set up a test-bed with Ribek's scene
 
 
-When doing viewport clear in DX11 it will only clear the first render target
-RenderTexturePool needs support for cube and 3D textures
-Load up and set up a test-bed with Ribek's scene
-Quantize buffer sizes so they're divideable by 8 when requesting them from RenderTexturePool
-
-R11G11B10 and R10G10B10A2 formats haven't been tested
-
-Rendering procedure should be:
- - For each camera go over each renderable and determine if their layers match
- - If they match do frustum culling
- - Add renderables to opaque or transparent queue depending on material
- - This should happen in renderAllCore before actual rendering starts
- - When rendering bind gbuffer render targets and render opaque queue
- - Unbind gbuffer and resolve to scene color
- - Bind scene color and render transparent queue
- - Resolve scene color to frame buffer (they could be the same target if no MSAA is used, and gamma correction is properly set)
- - After rendering is done make sure to clear the queues so I don't hold invalid references
-
-Store RenderTargets per camera
- - Only create it if camera is rendering some renderables
- - If none are rendered clear the reference to free the targets
+Notes:
+ - When doing viewport clear in DX11 it will only clear the first render target
+ - Quantize buffer sizes so they're divideable by 8 when requesting them from RenderTexturePool
+ - R11G11B10 and R10G10B10A2 formats haven't been tested
+ - Will need to ensure the code works in OpenGL (means porting shaders or building the cross compiler). I cannot delay 
+   this as later it will be hard to debug when the pipeline is more complex.
 
 
 Generate different RenderableController for each set of elements
 Generate different RenderableController for each set of elements
  - Will likely want to rename current LitTexRenderableController to OpaqueSomething
  - Will likely want to rename current LitTexRenderableController to OpaqueSomething
@@ -101,7 +88,7 @@ Later:
  - Proper PBR materials with reflection
  - Proper PBR materials with reflection
  - Post-processing system - FXAA, SSAO, Color correction, Depth of field (Bokeh)
  - Post-processing system - FXAA, SSAO, Color correction, Depth of field (Bokeh)
  - Forward rendering for transparent objects
  - Forward rendering for transparent objects
- - Occlusion
+ - Occlusion culling
  - GI
  - GI
  - Volumetric lighting
  - Volumetric lighting
  - SSR
  - SSR