Browse Source

Bunch of fixes for MeshHeap and related systems
GUIManager now uses MeshHeap

Marko Pintera 12 years ago
parent
commit
9bb801f889

+ 5 - 3
BansheeEngine/Include/BsGUIManager.h

@@ -30,8 +30,7 @@ namespace BansheeEngine
 				:isDirty(true)
 			{ }
 
-			CM::Vector<CM::HMesh>::type cachedMeshes;
-			CM::Vector<CM::UINT32>::type meshBufferSizes;
+			CM::Vector<CM::TransientMeshPtr>::type cachedMeshes;
 			CM::Vector<GUIMaterialInfo>::type cachedMaterials;
 			CM::Vector<GUIWidget*>::type cachedWidgetsPerMesh;
 			CM::Vector<GUIWidget*>::type widgets;
@@ -118,10 +117,13 @@ namespace BansheeEngine
 		};
 
 		static const CM::UINT32 DRAG_DISTANCE;
-		static const CM::UINT32 MESH_BUFFER_SIZE_INCREMENT;
+
+		static const CM::UINT32 MESH_HEAP_INITIAL_NUM_VERTS;
+		static const CM::UINT32 MESH_HEAP_INITIAL_NUM_INDICES;
 
 		CM::Vector<WidgetInfo>::type mWidgets;
 		CM::UnorderedMap<const CM::Viewport*, GUIRenderData>::type mCachedGUIData;
+		CM::MeshHeapPtr mMeshHeap;
 
 		CM::VertexDataDescPtr mVertexDesc;
 

+ 3 - 3
BansheeEngine/Source/BsDrawHelperTemplate.cpp

@@ -38,7 +38,7 @@ namespace BansheeEngine
 				if(mat == nullptr || !mat.isLoaded() || !mat->isInitialized())
 					continue;
 
-				renderQueue.add(mat, cmd.mesh, 0, cmd.worldCenter);
+				renderQueue.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
 			}
 			else if(cmd.type == DebugDrawType::ScreenSpace)
 			{
@@ -50,7 +50,7 @@ namespace BansheeEngine
 				cmd.matInfo2DScreenSpace.invViewportWidth.set(invViewportWidth);
 				cmd.matInfo2DScreenSpace.invViewportHeight.set(invViewportHeight);
 
-				renderQueue.add(mat, cmd.mesh, 0, cmd.worldCenter);
+				renderQueue.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
 			}
 			else if(cmd.type == DebugDrawType::WorldSpace)
 			{
@@ -61,7 +61,7 @@ namespace BansheeEngine
 
 				cmd.matInfo3D.matViewProj.set(viewProjMatrix);
 
-				renderQueue.add(mat, cmd.mesh, 0, cmd.worldCenter);
+				renderQueue.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
 			}
 		}
 

+ 15 - 26
BansheeEngine/Source/BsGUIManager.cpp

@@ -29,6 +29,8 @@
 #include "BsGUIDropDownBoxManager.h"
 #include "BsGUIContextMenu.h"
 #include "CmProfiler.h"
+#include "CmMeshHeap.h"
+#include "CmTransientMesh.h"
 
 using namespace CamelotFramework;
 namespace BansheeEngine
@@ -56,7 +58,8 @@ namespace BansheeEngine
 	};
 
 	const UINT32 GUIManager::DRAG_DISTANCE = 3;
-	const UINT32 GUIManager::MESH_BUFFER_SIZE_INCREMENT = 500;
+	const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_VERTS = 16384;
+	const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_INDICES = 49152;
 
 	GUIManager::GUIManager()
 		:mElementUnderCursor(nullptr), mWidgetUnderCursor(nullptr), mSeparateMeshesByWidget(true), mActiveElement(nullptr), 
@@ -88,6 +91,8 @@ namespace BansheeEngine
 		mVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
 		mVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
 
+		mMeshHeap = MeshHeap::create(MESH_HEAP_INITIAL_NUM_VERTS, MESH_HEAP_INITIAL_NUM_INDICES, mVertexDesc);
+
 		// Need to defer this call because I want to make sure all managers are initialized first
 		deferredCall(std::bind(&GUIManager::updateCaretTexture, this));
 		deferredCall(std::bind(&GUIManager::updateTextSelectionTexture, this));
@@ -173,7 +178,9 @@ namespace BansheeEngine
 			renderData.widgets.erase(findIter2);
 
 		if(renderData.widgets.size() == 0)
+		{
 			mCachedGUIData.erase(renderTarget);
+		}
 		else
 			renderData.isDirty = true;
 	}
@@ -259,7 +266,7 @@ namespace BansheeEngine
 					continue;
 				}
 
-				if(mesh == nullptr || !mesh.isLoaded())
+				if(mesh == nullptr)
 				{
 					meshIdx++;
 					continue;
@@ -269,7 +276,7 @@ namespace BansheeEngine
 				materialInfo.invViewportHeight.set(invViewportHeight);
 				materialInfo.worldTransform.set(widget->SO()->getWorldTfrm());
 
-				renderQueue.add(materialInfo.material, mesh, 0, Vector3::ZERO);
+				renderQueue.add(materialInfo.material.getInternalPtr(), mesh, 0, Vector3::ZERO);
 
 				meshIdx++;
 			}
@@ -457,10 +464,10 @@ namespace BansheeEngine
 
 			UINT32 numMeshes = (UINT32)sortedGroups.size();
 			UINT32 oldNumMeshes = (UINT32)renderData.cachedMeshes.size();
+
 			if(numMeshes < oldNumMeshes)
 			{
 				renderData.cachedMeshes.resize(numMeshes);
-				renderData.meshBufferSizes.resize(numMeshes);
 			}
 
 			renderData.cachedMaterials.resize(numMeshes);
@@ -509,32 +516,14 @@ namespace BansheeEngine
 					quadOffset += numQuads;
 				}
 
-				// Create new mesh if needed
-				if(groupIdx >= (UINT32)renderData.cachedMeshes.size())
+				if(groupIdx < (UINT32)renderData.cachedMeshes.size())
 				{
-					UINT32 bufferNumQuads = group->numQuads + MESH_BUFFER_SIZE_INCREMENT;
-
-					renderData.cachedMeshes.push_back(Mesh::create(bufferNumQuads * 4, bufferNumQuads * 6, mVertexDesc, meshData, MeshBufferType::Dynamic));
-					renderData.meshBufferSizes.push_back(bufferNumQuads);
-
-					renderData.cachedMeshes.back()->clearSubMeshes();
-					renderData.cachedMeshes.back()->addSubMesh(0, group->numQuads * 6);
+					mMeshHeap->dealloc(renderData.cachedMeshes[groupIdx]);
+					renderData.cachedMeshes[groupIdx] = mMeshHeap->alloc(meshData);
 				}
 				else
 				{
-					// Increase mesh size if it doesn't fit
-					if(renderData.meshBufferSizes[groupIdx] < group->numQuads)
-					{
-						UINT32 bufferNumQuads = group->numQuads + MESH_BUFFER_SIZE_INCREMENT;
-
-						renderData.cachedMeshes[groupIdx] = Mesh::create(bufferNumQuads * 4, bufferNumQuads * 6, mVertexDesc, MeshBufferType::Dynamic);
-						renderData.meshBufferSizes[groupIdx] = bufferNumQuads;
-					}
-
-					gMainCA().writeSubresource(renderData.cachedMeshes[groupIdx].getInternalPtr(), 0, meshData, true);
-
-					renderData.cachedMeshes[groupIdx]->clearSubMeshes();
-					renderData.cachedMeshes[groupIdx]->addSubMesh(0, group->numQuads * 6);
+					renderData.cachedMeshes.push_back(mMeshHeap->alloc(meshData));
 				}
 
 				groupIdx++;

+ 1 - 1
BansheeEngine/Source/BsRenderable.cpp

@@ -76,7 +76,7 @@ namespace BansheeEngine
 					}
 				}
 
-				renderQueue.add(mat, mMesh, i, mWorldBounds[i].getCenter());
+				renderQueue.add(mat.getInternalPtr(), mMesh.getInternalPtr(), i, mWorldBounds[i].getCenter());
 			}
 
 		}

+ 2 - 2
BansheeForwardRenderer/Source/BsForwardRenderer.cpp

@@ -185,7 +185,7 @@ namespace BansheeEngine
 			gProfiler().beginSample("renderG");
 
 			const RenderOperation& renderOp = *iter->baseOperation;
-			HMaterial material = renderOp.material;
+			MaterialPtr material = renderOp.material;
 
 			PassPtr pass = material->getPass(iter->passIdx);
 			pass->activate(coreAccessor);
@@ -200,7 +200,7 @@ namespace BansheeEngine
 			gProfiler().beginSample("renderI");
 
 			const SubMesh& subMesh = renderOp.mesh->getSubMesh(renderOp.submeshIdx);
-			coreAccessor.render(renderOp.mesh.getInternalPtr(), subMesh.indexOffset, subMesh.indexCount, true, subMesh.drawOp);
+			coreAccessor.render(renderOp.mesh, subMesh.indexOffset, subMesh.indexCount, true, subMesh.drawOp);
 
 			gProfiler().endSample("renderI");
 		}

+ 33 - 0
CSharpWrap.txt

@@ -46,6 +46,39 @@ Systems:
  - Input
  - Time
 
+ -----------------
+
+ But which ones will I need initially?
+  - [EditorApplication] - Entry point. Creates a MainEditorWindow
+  - [EditorWindow] (Scene, Project, Hierarchy, etc.)
+   - show()/hide()
+  - [MainEditorWindow]
+   - Slight variation of EditorWindow as there can be only one of them
+   - Contains [TitleBar], [DockManager]
+  - When adding GUI elements I need to make it easy to add game GUI elements,
+    but also make a distinction and make it possible to add editor GUI elements.
+	- Each EditorWindow contains a [GUIWidget] (created by default)
+	  - This GUIWIdget is created specially with EditorWindow as its target
+	- GUIWidget is also a Component which can be used for rendering to Game view
+	  - All game GUIWidgets are created with Game render target as their target
+  - [GameObject], [Component]
+    - Need something to add GUIWidget to
+  - I need to have [Application] running within EditorApplication
+    - So when I remove EditorApplication everything runs as normal
+	- How to make the distinction?
+	  - Application needs to render to RenderTarget when in editor, and have its own window when standalone
+	   - When in Editor, EditorApplication will call application and tell it to create a render target
+	   - When published I will have a Game class, which will also call Application and run it in a window
+	  - Certain components should only exists in editor (Like Scene camera, gizmos and etc.)
+	   - Add a flag to GameObjects like in Unity, that can hide the object in Hierarchy, or make it not save
+	   - Editor objects would be hidden and would not save with the level, which would make publishing work
+  - GUIWidget
+    - [GUILayoutX], [GUILayoutY], [GUIArea], [GUISpace], [GUIFlexibleSpace]
+	- [GUIElement]
+	  - [GUILabel], [GUIButton], etc.
+	- TODO: GUISkin? - Will I need to create interface for textures and resource loading/importing as well? Probably
+  
+
 
  -----------------
 

+ 2 - 2
CamelotClient/CamelotClient.cpp

@@ -35,9 +35,9 @@
 #include "CmRTTIType.h"
 #include "CmPlatform.h"
 
-#define DX11
+//#define DX11
 //#define DX9
-//#define GL
+#define GL
 
 using namespace CamelotFramework;
 using namespace BansheeEditor;

+ 1 - 1
CamelotClient/Source/BsDockManager.cpp

@@ -247,7 +247,7 @@ namespace BansheeEditor
 
 		mDropOverlayMat->setColor("highlightActive", highlightColor);
 
-		renderQueue.add(mDropOverlayMat, mDropOverlayMesh, 0, Vector3::ZERO);
+		renderQueue.add(mDropOverlayMat.getInternalPtr(), mDropOverlayMesh.getInternalPtr(), 0, Vector3::ZERO);
 	}
 
 	void DockManager::insert(EditorWidgetContainer* relativeTo, EditorWidget* widgetToInsert, DockLocation location)

+ 2 - 2
CamelotCore/Include/CmRenderOperation.h

@@ -11,8 +11,8 @@ namespace CamelotFramework
 		RenderOperation()
 		{ }
 
-		HMaterial material;
-		HMesh mesh;
+		MaterialPtr material;
+		MeshBasePtr mesh;
 		UINT32 submeshIdx;
 		Vector3 worldPosition;
 	};

+ 1 - 1
CamelotCore/Include/CmRenderQueue.h

@@ -19,7 +19,7 @@ namespace CamelotFramework
 	public:
 		RenderQueue();
 
-		void add(const HMaterial& material, const HMesh& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort);
+		void add(const MaterialPtr& material, const MeshBasePtr& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort);
 		void clear();
 		
 		virtual void sort() = 0;

+ 3 - 0
CamelotCore/Include/CmTransientMesh.h

@@ -51,7 +51,10 @@ namespace CamelotFramework
 		TransientMesh(const MeshHeapPtr& parentHeap, UINT32 id, UINT32 numIndices, 
 			UINT32 numVertices, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
+		void markAsDestroyed() { mIsDestroyed = true; }
+
 	protected:
+		bool mIsDestroyed;
 		MeshHeapPtr mParentHeap;
 		UINT32 mId;
 	};

+ 18 - 8
CamelotCore/Source/CmMeshHeap.cpp

@@ -54,6 +54,12 @@ namespace CamelotFramework
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
+		for(auto& cpuVertBuffer : mCPUVertexData)
+			cm_free(cpuVertBuffer);
+
+		if(mCPUIndexData != nullptr)
+			cm_free(mCPUIndexData);
+
 		CoreObject::destroy_internal();
 	}
 
@@ -81,6 +87,7 @@ namespace CamelotFramework
 		if(iterFind == mMeshes.end())
 			return;
 
+		mesh->markAsDestroyed();
 		mMeshes.erase(iterFind);
 
 		queueGpuCommand(getThisPtr(), boost::bind(&MeshHeap::deallocInternal, this, mesh->mId));
@@ -249,7 +256,7 @@ namespace CamelotFramework
 			VertexBufferPtr vertexBuffer = mVertexData->getBuffer(i);
 
 			UINT8* vertDest = mCPUVertexData[i] + vertChunkStart * vertSize;
-			memcpy(vertDest, meshData->getStreamData(i), vertChunkStart * vertSize);
+			memcpy(vertDest, meshData->getStreamData(i), meshData->getNumVertices() * vertSize);
 
 			if(vertexBuffer->vertexColorReqRGBFlip())
 			{
@@ -278,7 +285,7 @@ namespace CamelotFramework
 		UINT32 idxSize = indexBuffer->getIndexSize();
 
 		UINT8* idxDest = mCPUIndexData + idxChunkStart * idxSize;
-		memcpy(idxDest, meshData->getIndexData(), idxChunkStart * idxSize);
+		memcpy(idxDest, meshData->getIndexData(), meshData->getNumIndices() * idxSize);
 		indexBuffer->writeData(idxChunkStart * idxSize, meshData->getNumIndices() * idxSize, idxDest, BufferWriteType::NoOverwrite);
 	}
 
@@ -483,6 +490,7 @@ namespace CamelotFramework
 
 	void MeshHeap::freeEventQuery(UINT32 idx)
 	{
+		mEventQueries[idx].query->onTriggered.disconnect_all_slots();
 		mEventQueries[idx].queryId = 0;
 		mFreeEventQueries.push(idx);
 	}
@@ -573,16 +581,17 @@ namespace CamelotFramework
 				continue;
 
 			ChunkData& curChunk = mVertChunks[freeChunkIdx];
-			bool merged = false;
+			if(curChunk.size == 0) // Already merged
+				continue;
 
+			bool merged = false;
 			if(curChunk.start == (vertChunk.start + vertChunk.size))
 			{
 				vertChunk.size += curChunk.size;
 
 				merged = true;
 			}
-			
-			if((curChunk.start + curChunk.size) == vertChunk.start)
+			else if((curChunk.start + curChunk.size) == vertChunk.start)
 			{
 				vertChunk.start = curChunk.start;
 				vertChunk.size += curChunk.size;
@@ -608,16 +617,17 @@ namespace CamelotFramework
 				continue;
 
 			ChunkData& curChunk = mIdxChunks[freeChunkIdx];
-			bool merged = false;
+			if(curChunk.size == 0) // Already merged
+				continue;
 
+			bool merged = false;
 			if(curChunk.start == (idxChunk.start + idxChunk.size))
 			{
 				idxChunk.size += curChunk.size;
 
 				merged = true;
 			}
-
-			if((curChunk.start + curChunk.size) == idxChunk.start)
+			else if((curChunk.start + curChunk.size) == idxChunk.start)
 			{
 				idxChunk.start = curChunk.start;
 				idxChunk.size += curChunk.size;

+ 1 - 1
CamelotCore/Source/CmRenderQueue.cpp

@@ -14,7 +14,7 @@ namespace CamelotFramework
 		mSortedRenderOps.clear();
 	}
 
-	void RenderQueue::add(const HMaterial& material, const HMesh& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort)
+	void RenderQueue::add(const MaterialPtr& material, const MeshBasePtr& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort)
 	{
 		// TODO - Make sure RenderOperations are cached so we dont allocate memory for them every frame
 		mRenderOperations.push_back(RenderOperation());

+ 7 - 3
CamelotCore/Source/CmTransientMesh.cpp

@@ -5,15 +5,19 @@
 
 namespace CamelotFramework
 {
-	TransientMesh::TransientMesh(const MeshHeapPtr& parentHeap, UINT32 id, UINT32 numIndices, UINT32 numVertices, DrawOperationType drawOp)
-		:MeshBase(numVertices, numIndices, drawOp), mParentHeap(parentHeap), mId(id)
+	TransientMesh::TransientMesh(const MeshHeapPtr& parentHeap, UINT32 id, UINT32 numVertices, UINT32 numIndices, DrawOperationType drawOp)
+		:MeshBase(numVertices, numIndices, drawOp), mParentHeap(parentHeap), mId(id), mIsDestroyed(false)
 	{
 
 	}
 
 	TransientMesh::~TransientMesh()
 	{
-
+		if(!mIsDestroyed)
+		{
+			TransientMeshPtr meshPtr = std::static_pointer_cast<TransientMesh>(getThisPtr());
+			mParentHeap->dealloc(meshPtr);
+		}
 	}
 
 	void TransientMesh::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer)

+ 3 - 4
CamelotGLRenderer/Source/CmGLIndexBuffer.cpp

@@ -69,7 +69,6 @@ namespace CamelotFramework
         UINT32 length, GpuLockOptions options)
     {
         GLenum access = 0;
-
         if(mIsLocked)
         {
             CM_EXCEPT(InternalErrorException, 
@@ -99,7 +98,7 @@ namespace CamelotFramework
 			CM_EXCEPT(InternalErrorException, "Index Buffer: Out of memory");
 		}
 
-		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer) + offset);
+		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer));
 
 		mIsLocked = true;
 		return retPtr;
@@ -107,9 +106,9 @@ namespace CamelotFramework
 
 	void GLIndexBuffer::unlockImpl(void)
     {
-		glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId);
 
-		if(!glUnmapBuffer(GL_ARRAY_BUFFER))
+		if(!glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER))
 		{
 			CM_EXCEPT(InternalErrorException, "Buffer data corrupted, please reload");
 		}

+ 0 - 1
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -715,7 +715,6 @@ namespace CamelotFramework
 			static_cast<GLIndexBuffer*>(mBoundIndexBuffer.get())->getGLBufferId());
 
 		GLenum indexType = (mBoundIndexBuffer->getType() == IndexBuffer::IT_16BIT) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
-
 		glDrawElementsBaseVertex(primType, indexCount, indexType, (GLvoid*)(mBoundIndexBuffer->getIndexSize() * startIndex), vertexOffset);
 
 		endDraw();

+ 1 - 1
CamelotGLRenderer/Source/CmGLVertexBuffer.cpp

@@ -75,7 +75,7 @@ namespace CamelotFramework
 			CM_EXCEPT(InternalErrorException, "Vertex Buffer: Out of memory");
 		}
 
-		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer) + offset);
+		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer));
 
 		mIsLocked = true;
 		return retPtr;

+ 1 - 7
Opts.txt

@@ -20,11 +20,5 @@ When optimizing UpdateLayout make sure to mark elements that are fully culled as
 
 ----------
 
-BIG TODO FINALLY: Reorganize GUI so it all uses one big vertex buffer (probably in the form of a TransientMesh). This means I need better support for drawing individual objects
-from a transient mesh by drawing only parts of its buffer. But only do this after I have optimized and tested the normal mesh (on all render systems)
-
-
-----------
-
-When writing to buffer in MeshHeap (in two places at least) I need to add NO_OVERWITE flag to HardwareBuffer
+Fix OpenGL MeshHeap. All the meshes are rendering corrupted
 When doing allocInternal I don't check that index/vertex desc in MeshData actually matches the ones in MeshHeap.