Ver Fonte

Added a special class for the core thread

Marko Pintera há 12 anos atrás
pai
commit
2e7b129c54

+ 3 - 3
BansheeEngine/Source/BsDebugDraw.cpp

@@ -155,9 +155,9 @@ namespace BansheeEngine
 			}
 		}
 
-		gMainSyncedRC().writeSubresource(mLineMesh.getInternalPtr(), 0, *lineMeshData);
-		gMainSyncedRC().writeSubresource(mTriangleMesh.getInternalPtr(), 0, *triangleMeshData);
-		gMainSyncedRC().submitToGpu(true);
+		gMainSyncedCA().writeSubresource(mLineMesh.getInternalPtr(), 0, *lineMeshData);
+		gMainSyncedCA().writeSubresource(mTriangleMesh.getInternalPtr(), 0, *triangleMeshData);
+		gMainSyncedCA().submitToGpu(true);
 	}
 
 	void DebugDraw::render(const Camera* camera, RenderContext& renderContext)

+ 2 - 2
BansheeEngine/Source/BsGUIManager.cpp

@@ -402,8 +402,8 @@ namespace BansheeEngine
 					renderData.cachedMeshes.push_back(Mesh::create());
 				}
 
-				gMainSyncedRC().writeSubresource(renderData.cachedMeshes[groupIdx].getInternalPtr(), 0, *meshData);
-				gMainSyncedRC().submitToGpu(true); // TODO - Remove this once I make writeSubresource accept a shared_ptr for MeshData
+				gMainSyncedCA().writeSubresource(renderData.cachedMeshes[groupIdx].getInternalPtr(), 0, *meshData);
+				gMainSyncedCA().submitToGpu(true); // TODO - Remove this once I make writeSubresource accept a shared_ptr for MeshData
 
 				groupIdx++;
 			}

+ 2 - 2
BansheeForwardRenderer/Source/BsForwardRenderer.cpp

@@ -33,7 +33,7 @@ namespace BansheeEngine
 
 	void ForwardRenderer::renderAll() 
 	{
-		RenderContext& renderContext = gMainRC();
+		RenderContext& renderContext = gMainCA();
 		const Vector<HCamera>::type& allCameras = gSceneManager().getAllCameras();
 
 		// Find all unique render targets
@@ -83,7 +83,7 @@ namespace BansheeEngine
 		if(!camera->getIgnoreSceneRenderables())
 			allRenderables = gSceneManager().getVisibleRenderables(camera);
 
-		RenderContext& renderContext = gMainRC();
+		RenderContext& renderContext = gMainCA();
 		renderContext.setViewport(camera->getViewport());
 
 		Matrix4 projMatrixCstm = camera->getProjectionMatrix();

+ 2 - 2
CamelotClient/CamelotClient.cpp

@@ -278,8 +278,8 @@ int CALLBACK WinMain(
 	HTexture dbgCursor = static_resource_cast<Texture>(Importer::instance().import("C:\\CursorDbg.psd"));
 	PixelDataPtr cursorPixelData = dbgCursor->allocateSubresourceBuffer(0);
 
-	gMainSyncedRC().readSubresource(dbgCursor.getInternalPtr(), 0, *cursorPixelData);
-	gMainSyncedRC().submitToGpu(true);
+	gMainSyncedCA().readSubresource(dbgCursor.getInternalPtr(), 0, *cursorPixelData);
+	gMainSyncedCA().submitToGpu(true);
 
 	//Cursor::setCustomCursor(*cursorPixelData, Int2(0, 0));
 

+ 2 - 0
CamelotCore/CamelotCore.vcxproj

@@ -176,6 +176,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="Include\CmCoreThread.h" />
     <ClInclude Include="Include\CmDeferredRenderContextFwd.h" />
     <ClInclude Include="Include\CmGameObjectHandle.h" />
     <ClInclude Include="Include\CmGameObject.h" />
@@ -300,6 +301,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Include\CmMaterialManager.cpp" />
+    <ClCompile Include="Source\CmCoreThread.cpp" />
     <ClCompile Include="Source\CmGameObjectHandle.cpp" />
     <ClCompile Include="Source\CmGameObject.cpp" />
     <ClCompile Include="Source\CmApplication.cpp" />

+ 6 - 0
CamelotCore/CamelotCore.vcxproj.filters

@@ -450,6 +450,9 @@
     <ClInclude Include="Include\CmInputFwd.h">
       <Filter>Header Files\Input</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmCoreThread.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmApplication.cpp">
@@ -692,5 +695,8 @@
     <ClCompile Include="Source\CmOSInputHandler.cpp">
       <Filter>Source Files\Input</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmCoreThread.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 9 - 9
CamelotCore/Include/CmApplication.h

@@ -78,8 +78,8 @@ namespace CamelotFramework
 			boost::signal<void()> mainLoopCallback;
 
 	private:
-		friend CM_EXPORT RenderContext& gMainRC();
-		friend CM_EXPORT SyncedRenderContext& gMainSyncedRC();
+		friend CM_EXPORT RenderContext& gMainCA();
+		friend CM_EXPORT SyncedRenderContext& gMainSyncedCA();
 
 		RenderWindowPtr mPrimaryWindow;
 		RenderContextPtr mPrimaryRenderContext;
@@ -104,18 +104,18 @@ namespace CamelotFramework
 	CM_EXPORT Application& gApplication();
 
 	/**
-	 * @brief	A shortcut for accessing the primary render context. This render context may only be accessed safely
+	 * @brief	A shortcut for accessing the primary core accessor. It may only be accessed safely
 	 * 			from the main thread.
 	 */
-	CM_EXPORT RenderContext& gMainRC();
+	CM_EXPORT RenderContext& gMainCA();
 
 	/**
-	 * @brief	A shortcut for accessing the primary synchronized render context. This context may be accessed
-	 * 			from all threads except the render thread. All operations from this context will be executed after
-	 * 			non-synchronized primary context has finished executing.
+	 * @brief	A shortcut for accessing the primary synchronized core accessor. This context may be accessed
+	 * 			from all threads except the render thread. All operations from this accessor will be executed after
+	 * 			non-synchronized primary accessor has finished executing.
 	 * 			
-	 * @note	It is more efficient to create your own non-synchronized render context if you plan on often using the render context from
+	 * @note	It is more efficient to create your own non-synchronized core accessor if you plan on often using it from
 	 * 			threads other than main.
 	 */
-	CM_EXPORT SyncedRenderContext& gMainSyncedRC();
+	CM_EXPORT SyncedRenderContext& gMainSyncedCA();
 }

+ 142 - 0
CamelotCore/Include/CmCoreThread.h

@@ -0,0 +1,142 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmModule.h"
+#include "CmCommandQueue.h"
+#include "CmDeferredRenderContext.h"
+
+namespace CamelotFramework
+{
+	/**
+	 * @brief	Manager for the core thread. Takes care of starting, running, queuing commands
+	 * 			and shutting down the core thread.
+	 */
+	class CM_EXPORT CoreThread : public Module<CoreThread>
+	{
+public:
+	CoreThread();
+	~CoreThread();
+
+	/**
+		* @brief	Returns the id of the core thread. If a separate core thread
+		* 			is not used, then it returns the id of the thread RenderSystem
+		* 			was initialized on.
+		*/
+	CM_THREAD_ID_TYPE getCoreThreadId() { return mCoreThreadId; }
+
+	/**
+		* @brief	Creates an accessor that you can use for executing commands on the core thread from 
+		* 			a non-core thread. You can have as many of these as you wish, the only limitation
+		* 			is that you do not use a single instance on more than one thread. Each thread
+		* 			requires its own accessor. The accessor will be bound to the thread you call this method on.
+		*/
+	RenderContextPtr createAccessor();
+
+	/**
+	* @brief	Retrieves an accessor that you can use for executing commands on the core thread from
+	* 			a non-core thread. There is only one synchronized accessor and you may access it from any thread you wish.
+	* 			Note however that it is much more efficient to create a separate non-synchronized accessor using
+	* 			"createCoreAccessor" for each thread you will be using it on.
+		*/
+	SyncedRenderContext& getSyncedAccessor();
+
+	/**
+		* @brief	Queues a new command that will be added to the global command queue. You are allowed to call this from any thread,
+		* 			however be aware that it involves possibly slow synchronization primitives, so limit your usage.
+		* 			
+		* @param	blockUntilComplete If true the thread will be blocked until the command executes. Be aware that there be many commands queued before it
+		* 							   and they all need to be executed in order before the current command is reached, which might take a long time.
+		* 	
+		* @see		CommandQueue::queueReturn
+		*/
+	AsyncOp queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete = false);
+
+	/**
+	* @brief	Queues a new command that will be added to the global command queue.You are allowed to call this from any thread,
+		* 			however be aware that it involves possibly slow synchronization primitives, so limit your usage.
+		* 	
+		* @param	blockUntilComplete If true the thread will be blocked until the command executes. Be aware that there be many commands queued before it
+		* 							   and they all need to be executed in order before the current command is reached, which might take a long time.
+		* @see		CommandQueue::queue
+		*/
+	void queueCommand(boost::function<void()> commandCallback, bool blockUntilComplete = false);
+
+private:
+	class CoreThreadWorkerFunc CM_THREAD_WORKER_INHERIT
+	{
+	public:
+		CoreThreadWorkerFunc(CoreThread* owner);
+
+		void operator()();
+
+	private:
+		CoreThread* mOwner;
+	};
+
+	CoreThreadWorkerFunc* mCoreThreadFunc;
+	volatile bool mCoreThreadStarted;
+	volatile bool mCoreThreadShutdown;
+
+	CM_THREAD_ID_TYPE mCoreThreadId;
+	CM_THREAD_SYNCHRONISER(mCoreThreadStartCondition)
+	CM_MUTEX(mCoreThreadStartMutex)
+	CM_MUTEX(mCommandQueueMutex)
+	CM_THREAD_SYNCHRONISER(mCommandReadyCondition)
+	CM_MUTEX(mCommandNotifyMutex)
+	CM_THREAD_SYNCHRONISER(mCommandCompleteCondition)
+
+#if CM_THREAD_SUPPORT
+	CM_THREAD_TYPE* mCoreThread;
+#endif
+
+	CommandQueue<CommandQueueSync>* mCommandQueue;
+
+	UINT32 mMaxCommandNotifyId; // ID that will be assigned to the next command with a notifier callback
+	Vector<UINT32>::type mCommandsCompleted; // Completed commands that have notifier callbacks set up
+
+	SyncedRenderContext* mSyncedCoreAccessor;
+
+	/**
+		* @brief	Initializes a separate core thread. Should only be called once.
+		*/
+	void initCoreThread();
+
+	/**
+		* @brief	Main function of the core thread. Called once thread is started.
+		*/
+	void runCoreThread();
+
+	/**
+		* @brief	Shutdowns the core thread. It will complete all ready commands
+		* 			before shutdown.
+		*/
+	void shutdownCoreThread();
+
+	/**
+		* @brief	Blocks the calling thread until the command with the specified ID completes.
+		* 			Make sure that the specified ID actually exists, otherwise this will block forever.
+		*/
+	void blockUntilCommandCompleted(UINT32 commandId);
+
+	/**
+		* @brief	Callback called by the command list when a specific command finishes executing.
+		* 			This is only called on commands that have a special notify on complete flag set.
+		*
+		* @param	commandId	Identifier for the command.
+		*/
+	void commandCompletedNotify(UINT32 commandId);
+	};
+
+	CM_EXPORT CoreThread& gCoreThread();
+
+	/**
+		* @brief	Throws an exception if current thread isn't the core thread;
+		*/
+	static void throwIfNotCoreThread();
+
+#if CM_DEBUG_MODE
+#define THROW_IF_NOT_CORE_THREAD throwIfNotCoreThread();
+#else
+#define THROW_IF_NOT_CORE_THREAD 
+#endif
+}

+ 4 - 4
CamelotCore/Include/CmTextureRTTI.h

@@ -39,8 +39,8 @@ namespace CamelotFramework
 
 			GpuResourcePtr sharedTexPtr = std::static_pointer_cast<GpuResource>(obj->getThisPtr());
 
-			gMainSyncedRC().readSubresource(sharedTexPtr, subresourceIdx, *pixelData);
-			gMainSyncedRC().submitToGpu(true); // We need the data right away, so execute the context and wait until we get it
+			gMainSyncedCA().readSubresource(sharedTexPtr, subresourceIdx, *pixelData);
+			gMainSyncedCA().submitToGpu(true); // We need the data right away, so execute the context and wait until we get it
 
 			return pixelData;
 		}
@@ -113,10 +113,10 @@ namespace CamelotFramework
 				UINT32 subresourceIdx = texture->mapToSubresourceIdx(face, mipmap);
 
 				GpuResourcePtr sharedTexPtr = std::static_pointer_cast<GpuResource>(texture->getThisPtr());
-				gMainSyncedRC().writeSubresource(sharedTexPtr, subresourceIdx, *pixelData->at(i));
+				gMainSyncedCA().writeSubresource(sharedTexPtr, subresourceIdx, *pixelData->at(i));
 			}
 
-			gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+			gMainSyncedCA().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 
 			cm_delete<PoolAlloc>(pixelData);
 			texture->mRTTIData = nullptr;	

+ 5 - 2
CamelotCore/Source/CmApplication.cpp

@@ -26,6 +26,7 @@
 #include "CmFontManager.h"
 #include "CmRenderWindowManager.h"
 #include "CmRenderer.h"
+#include "CmCoreThread.h"
 
 #include "CmMaterial.h"
 #include "CmShader.h"
@@ -53,6 +54,7 @@ namespace CamelotFramework
 		Resources::startUp(cm_new<Resources>(desc.resourceCacheDirectory));
 		HighLevelGpuProgramManager::startUp(cm_new<HighLevelGpuProgramManager>());
 
+		CoreThread::startUp(cm_new<CoreThread>());
 		RenderSystemManager::startUp(cm_new<RenderSystemManager>());
 
 		mPrimaryWindow = RenderSystemManager::instance().initialize(desc.renderSystem, desc.primaryWindowDesc);
@@ -159,6 +161,7 @@ namespace CamelotFramework
 
 		RendererManager::shutDown();
 		RenderSystem::shutDown();
+		CoreThread::shutDown();
 		Input::shutDown();
 
 		HighLevelGpuProgramManager::shutDown();
@@ -218,12 +221,12 @@ namespace CamelotFramework
 		return application;
 	}
 
-	RenderContext& gMainRC()
+	RenderContext& gMainCA()
 	{
 		return *gApplication().mPrimaryRenderContext.get();
 	}
 
-	SyncedRenderContext& gMainSyncedRC()
+	SyncedRenderContext& gMainSyncedCA()
 	{
 		return *gApplication().mPrimarySyncedRenderContext;
 	}

+ 253 - 0
CamelotCore/Source/CmCoreThread.cpp

@@ -0,0 +1,253 @@
+#include "CmCoreThread.h"
+
+namespace CamelotFramework
+{
+	CoreThread::CoreThread()
+		: mCoreThreadFunc(nullptr)
+		, mCoreThreadStarted(false)
+		, mCoreThreadShutdown(false)
+		, mCommandQueue(nullptr)
+		, mMaxCommandNotifyId(0)
+		, mSyncedCoreAccessor(nullptr)
+	{
+		mCoreThreadId = CM_THREAD_CURRENT_ID;
+		mCommandQueue = cm_new<CommandQueue<CommandQueueSync>>(CM_THREAD_CURRENT_ID, true);
+
+		initCoreThread();
+	}
+
+	CoreThread::~CoreThread()
+	{
+		// TODO - What if something gets queued between the queued call to destroy_internal and this!?
+		shutdownCoreThread();
+
+		if(mCommandQueue != nullptr)
+		{
+			cm_delete(mCommandQueue);
+			mCommandQueue = nullptr;
+		}
+	}
+
+	void CoreThread::initCoreThread()
+	{
+#if !CM_FORCE_SINGLETHREADED_RENDERING
+		mCoreThreadFunc = cm_new<CoreThreadWorkerFunc>(this);
+
+#if CM_THREAD_SUPPORT
+		CM_THREAD_CREATE(t, *mCoreThreadFunc);
+		mCoreThread = t;
+
+		CM_LOCK_MUTEX_NAMED(mCoreThreadStartMutex, lock);
+
+		while(!mCoreThreadStarted)
+			CM_THREAD_WAIT(mCoreThreadStartCondition, mCoreThreadStartMutex, lock);
+
+#else
+		CM_EXCEPT(InternalErrorException, "Attempting to start a core thread but Camelot isn't compiled with thread support.");
+#endif
+#endif
+	}
+
+	void CoreThread::runCoreThread()
+	{
+#if !CM_FORCE_SINGLETHREADED_RENDERING
+		mCoreThreadId = CM_THREAD_CURRENT_ID;
+		mSyncedCoreAccessor = cm_new<DeferredRenderContext<CommandQueueSync>>(nullptr, CM_THREAD_CURRENT_ID);
+
+		{
+			CM_LOCK_MUTEX(mCoreThreadStartMutex);
+
+			mCoreThreadStarted = true;
+		}
+
+		CM_THREAD_NOTIFY_ALL(mCoreThreadStartCondition)
+
+		while(true)
+		{
+			// Wait until we get some ready commands
+			Queue<QueuedCommand>::type* commands = nullptr;
+			{
+				CM_LOCK_MUTEX_NAMED(mCommandQueueMutex, lock)
+
+				while(mCommandQueue->isEmpty())
+				{
+					if(mCoreThreadShutdown)
+						return;
+
+					CM_THREAD_WAIT(mCommandReadyCondition, mCommandQueueMutex, lock);
+				}
+
+				commands = mCommandQueue->flush();
+			}
+
+			// Play commands
+			mCommandQueue->playback(commands, boost::bind(&CoreThread::commandCompletedNotify, this, _1)); 
+		}
+
+		cm_delete(mSyncedCoreAccessor);
+#endif
+	}
+
+	void CoreThread::shutdownCoreThread()
+	{
+#if !CM_FORCE_SINGLETHREADED_RENDERING
+
+		{
+			CM_LOCK_MUTEX(mCommandQueueMutex);
+			mCoreThreadShutdown = true;
+		}
+
+		// Wake all threads. They will quit after they see the shutdown flag
+		CM_THREAD_NOTIFY_ALL(mCommandReadyCondition);
+
+		mCoreThread->join();
+		CM_THREAD_DESTROY(mCoreThread);
+
+		mCoreThread = nullptr;
+		mCoreThreadId = CM_THREAD_CURRENT_ID;
+
+		if(mCoreThreadFunc != nullptr)
+		{
+			cm_delete(mCoreThreadFunc);
+			mCoreThreadFunc = nullptr;
+		}
+#endif
+
+		mCoreThreadStarted = false;
+	}
+
+	RenderContextPtr CoreThread::createAccessor()
+	{
+		return cm_shared_ptr<DeferredRenderContext<CommandQueueNoSync>>(nullptr, CM_THREAD_CURRENT_ID);
+	}
+
+	SyncedRenderContext& CoreThread::getSyncedAccessor()
+	{
+		return *mSyncedCoreAccessor;
+	}
+
+	AsyncOp CoreThread::queueReturnCommand(boost::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete)
+	{
+		AsyncOp op;
+
+		if(CM_THREAD_CURRENT_ID == getCoreThreadId())
+		{
+			commandCallback(op); // Execute immediately
+			return op;
+		}
+
+		UINT32 commandId = -1;
+		{
+			CM_LOCK_MUTEX(mCommandQueueMutex);
+
+			if(blockUntilComplete)
+			{
+				commandId = mMaxCommandNotifyId++;
+				op = mCommandQueue->queueReturn(commandCallback, true, commandId);
+			}
+			else
+				op = mCommandQueue->queueReturn(commandCallback);
+		}
+
+		CM_THREAD_NOTIFY_ALL(mCommandReadyCondition);
+
+		if(blockUntilComplete)
+			blockUntilCommandCompleted(commandId);
+
+		return op;
+	}
+
+	void CoreThread::queueCommand(boost::function<void()> commandCallback, bool blockUntilComplete)
+	{
+		if(CM_THREAD_CURRENT_ID == getCoreThreadId())
+		{
+			commandCallback(); // Execute immediately
+			return;
+		}
+
+		UINT32 commandId = -1;
+		{
+			CM_LOCK_MUTEX(mCommandQueueMutex);
+
+			if(blockUntilComplete)
+			{
+				commandId = mMaxCommandNotifyId++;
+				mCommandQueue->queue(commandCallback, true, commandId);
+			}
+			else
+				mCommandQueue->queue(commandCallback);
+		}
+
+		CM_THREAD_NOTIFY_ALL(mCommandReadyCondition);
+
+		if(blockUntilComplete)
+			blockUntilCommandCompleted(commandId);
+	}
+
+	void CoreThread::blockUntilCommandCompleted(UINT32 commandId)
+	{
+#if !CM_FORCE_SINGLETHREADED_RENDERING
+		CM_LOCK_MUTEX_NAMED(mCommandNotifyMutex, lock);
+
+		while(true)
+		{
+			// TODO - This might be causing a deadlock in Release mode. I'm thinking because mCommandsCompleted isn't marked as volatile.
+
+			// Check if our command id is in the completed list
+			auto iter = mCommandsCompleted.begin();
+			for(; iter != mCommandsCompleted.end(); ++iter)
+			{
+				if(*iter == commandId)
+					break;
+			}
+
+			if(iter != mCommandsCompleted.end())
+			{
+				mCommandsCompleted.erase(iter);
+				break;
+			}
+
+			CM_THREAD_WAIT(mCommandCompleteCondition, mCommandNotifyMutex, lock);
+		}
+#endif
+	}
+
+	void CoreThread::commandCompletedNotify(UINT32 commandId)
+	{
+		{
+			CM_LOCK_MUTEX(mCommandNotifyMutex);
+
+			mCommandsCompleted.push_back(commandId);
+		}
+
+		CM_THREAD_NOTIFY_ALL(mCommandCompleteCondition);
+	}
+
+	CoreThread& gCoreThread()
+	{
+		return CoreThread::instance();
+	}
+
+	void throwIfNotCoreThread()
+	{
+#if !CM_FORCE_SINGLETHREADED_RENDERING
+		if(CM_THREAD_CURRENT_ID != CoreThread::instance().getCoreThreadId())
+			CM_EXCEPT(InternalErrorException, "Calling the render system from a non-render thread!");
+#endif
+	}
+
+	/************************************************************************/
+	/* 								THREAD WORKER                      		*/
+	/************************************************************************/
+
+	CoreThread::CoreThreadWorkerFunc::CoreThreadWorkerFunc(CoreThread* owner)
+		:mOwner(owner)
+	{
+		assert(mOwner != nullptr);
+	}
+
+	void CoreThread::CoreThreadWorkerFunc::operator()()
+	{
+		mOwner->runCoreThread();
+	}
+}

+ 1 - 1
CamelotCore/Source/CmMeshManager.cpp

@@ -50,7 +50,7 @@ namespace CamelotFramework
 		indices[1] = 0;
 		indices[2] = 0;
 
-		SyncedRenderContext& renderContext = gMainSyncedRC();
+		SyncedRenderContext& renderContext = gMainSyncedCA();
 
 		mDummyMesh = Mesh::create();
 		renderContext.writeSubresource(mDummyMesh.getInternalPtr(), 0, *mDummyMeshData);

+ 4 - 4
CamelotCore/Source/CmMeshRTTI.h

@@ -16,8 +16,8 @@ namespace CamelotFramework
 
 			GpuResourcePtr sharedMeshPtr = std::static_pointer_cast<GpuResource>(obj->getThisPtr());
 
-			gMainSyncedRC().readSubresource(sharedMeshPtr, 0, *meshData);
-			gMainSyncedRC().submitToGpu(true); // We need the data right away, so execute the context and wait until we get it
+			gMainSyncedCA().readSubresource(sharedMeshPtr, 0, *meshData);
+			gMainSyncedCA().submitToGpu(true); // We need the data right away, so execute the context and wait until we get it
 
 			return meshData;
 		}
@@ -26,8 +26,8 @@ namespace CamelotFramework
 		{ 
 			GpuResourcePtr sharedMeshPtr = std::static_pointer_cast<GpuResource>(obj->getThisPtr());
 
-			gMainSyncedRC().writeSubresource(sharedMeshPtr, 0, *meshData);
-			gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+			gMainSyncedCA().writeSubresource(sharedMeshPtr, 0, *meshData);
+			gMainSyncedCA().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 		}
 
 	public:

+ 2 - 2
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -51,8 +51,8 @@ namespace CamelotFramework
 		HMesh mesh = Mesh::create();
 
 		mesh.waitUntilLoaded();
-		gMainSyncedRC().writeSubresource(mesh.getInternalPtr(), 0, *meshData);
-		gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+		gMainSyncedCA().writeSubresource(mesh.getInternalPtr(), 0, *meshData);
+		gMainSyncedCA().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 
 		return mesh;
 	}

+ 2 - 2
CamelotFontImporter/Source/CmFontImporter.cpp

@@ -272,8 +272,8 @@ namespace CamelotFramework
 				newTex.waitUntilLoaded();
 
 				UINT32 subresourceIdx = newTex->mapToSubresourceIdx(0, 0);
-				gMainSyncedRC().writeSubresource(newTex.getInternalPtr(), subresourceIdx, pixelData);
-				gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+				gMainSyncedCA().writeSubresource(newTex.getInternalPtr(), subresourceIdx, pixelData);
+				gMainSyncedCA().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 
 				fontData.texturePages.push_back(newTex);
 

+ 2 - 2
CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp

@@ -135,8 +135,8 @@ namespace CamelotFramework
 			PixelData src = imgData->getPixels(mip);
 
 			UINT32 subresourceIdx = newTexture->mapToSubresourceIdx(0, mip);
-			gMainSyncedRC().writeSubresource(newTexture.getInternalPtr(), subresourceIdx, src);
-			gMainSyncedRC().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
+			gMainSyncedCA().writeSubresource(newTexture.getInternalPtr(), subresourceIdx, src);
+			gMainSyncedCA().submitToGpu(true); // TODO - Possibly we can avoid this. I don't see a reason we need to wait for the update to complete.
 		}
 
 		fileData->close();

+ 4 - 16
TODO.txt

@@ -24,31 +24,19 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
 /************** INPUT REFACTOR *********************/
 
 DO LATER:
- - Modifiyng Input focusChange so it gets called from WindowManager
-  - After I do remove the HWND == 0 check from Input
  - onMovedOrResized is still used by Viewport
  - Replace list of windows in WIndowEventUtilities with WindowManagers list. No need to keep two lists I think
  - Remagine render thread:
    - Its main loop is in CmApplication
    - Rename it to CoreThread
-------------
-
-How to design OSInputHandler and how does it interact with msg loop?
- - Set up key up/down callbacks, and mouse moved callbacks on the main loop
-
-How do I deal with window focus changes for newly created windows (no HWND)?
- - Calling setFocus(true) on a window calls WindowManager who registers a focus change
- - WindowManager::update (called from Application main thread) then triggers actual calls to setFocus and triggers focusChanged events
-   - Potentially remove focus events from RenderWindow (used by GUI) and use WindowManager directly
- - This also solves a problem that ATM focus changes are actually being called directly from render thread which is WRONG! (setFocus called from msg loop directly)
+   - Renamed DeferredRenderContext to DeferredCoreThreadAccessor
+ - Maybe: Attempt to add a global throwIfNotCore thread method
 
 /*******************************************************/
 
 IMMEDIATE:
- - Get rid of querying mouse states on each mouse event - Include button states in each event?
- - Handle capital leters - include shift, alt, ctrl, caps states in KeyEvent
-  - GetAsyncKeyState - possibly can be used for querying Caps Lock state. - Hook that to _translateText and update OIS notes (so I know I need that in Linux/Mac as well)
- - Ignore input when other window has focus - Possibly foreground mode but switch window input? (Will likely need multiple OIS input handlers...) (Possibly just calling SetCooperativeLevel will work)
+ - Update debug camera so it uses callbacks
+ - Add support for diacritical marks
  - Add window-management command to DeferredRenderContext - I already have resource management commands
    there, few window related ones won't hurt. I can always split the class if needed.
      - Possibly add guards to render target classes so they aren't accidentaly accessed from the render thread (similar to how Texture is handled)