浏览代码

Moved some of TextUtility allocations into vectors instead of doing each manually, hoping to reduce total alloc count

Marko Pintera 12 年之前
父节点
当前提交
63de13b0ab

+ 6 - 6
BansheeEngine/Source/BsTextSprite.cpp

@@ -20,13 +20,13 @@ namespace BansheeEngine
 		if(textData == nullptr)
 			return;
 
-		const std::vector<TextUtility::TextLine*>& lines = textData->getLines();
+		const std::vector<TextUtility::TextLine>& lines = textData->getLines();
 		const std::vector<UINT32>& quadsPerPage = textData->getNumQuadsPerPage();
 
 		UINT32 curHeight = 0;
 		for(auto& line : lines)
 		{
-			curHeight += line->getYOffset();
+			curHeight += line.getYOffset();
 		}
 
 		// Calc vertical alignment offset
@@ -92,22 +92,22 @@ namespace BansheeEngine
 				horzOffset = 0;
 				break;
 			case THA_Right:
-				horzOffset = std::max(0, (INT32)(desc.width - lines[i]->getWidth()));
+				horzOffset = std::max(0, (INT32)(desc.width - lines[i].getWidth()));
 				break;
 			case THA_Center:
-				horzOffset = std::max(0, (INT32)(desc.width - lines[i]->getWidth())) / 2;
+				horzOffset = std::max(0, (INT32)(desc.width - lines[i].getWidth())) / 2;
 				break;
 			}
 
 			Int2 position = offset + Int2(horzOffset, vertOffset + curY);
-			curY += lines[i]->getYOffset();
+			curY += lines[i].getYOffset();
 
 			for(size_t j = 0; j < numPages; j++)
 			{
 				SpriteRenderElement& renderElem = mCachedRenderElements[j];
 				UINT32 offset = faceOffsets[j];
 
-				UINT32 writtenQuads = lines[i]->fillBuffer((UINT32)j, renderElem.vertices, renderElem.uvs, renderElem.indexes, offset, renderElem.numQuads);
+				UINT32 writtenQuads = lines[i].fillBuffer((UINT32)j, renderElem.vertices, renderElem.uvs, renderElem.indexes, offset, renderElem.numQuads);
 				
 				UINT32 numVertices = writtenQuads * 4;
 				for(size_t i = 0; i < numVertices; i++)

+ 0 - 6
CamelotClient/CamelotClient.cpp

@@ -30,9 +30,6 @@
 #include "CmRTTIType.h"
 #include "CmCursor.h"
 
-#include "CmMemBlockPool.h"
-
-
 #define DX11
 //#define DX9
 //#define GL
@@ -66,9 +63,6 @@ int CALLBACK WinMain(
 	//CommandQueue::addBreakpoint(0, 22);
 	//CommandQueue::addBreakpoint(0, 12);
 
-	MemBlockPool<> blockPool;
-	void* someMemory = blockPool.alloc(32);
-
 	RenderSystem* renderSystem = RenderSystem::instancePtr();
 	RenderWindowPtr renderWindow = gApplication().getPrimaryWindow();
 

+ 5 - 5
CamelotCore/Include/CmTextUtility.h

@@ -83,14 +83,14 @@ namespace CamelotFramework
 			UINT32 mBaselineOffset;
 			UINT32 mLineHeight;
 			UINT32 mSpaceWidth;
-			vector<TextWord*>::type mWords;
+			vector<TextWord>::type mWords;
 			TextWord* mLastWord;
 
 			void add(const CHAR_DESC& charDesc);
 			void addSpace();
-			void addWord(TextWord* word);
+			void addWord(const TextWord& word);
 
-			TextWord* removeLastWord();
+			TextWord removeLastWord();
 
 			void calculateBounds();
 		};
@@ -100,7 +100,7 @@ namespace CamelotFramework
 		public:
 			~TextData();
 
-			const std::vector<TextLine*>& getLines() const { return mLines; }
+			const std::vector<TextLine>& getLines() const { return mLines; }
 			const std::vector<HTexture>& getTexturePages() const { return mTexturePages; }
 			const std::vector<UINT32>& getNumQuadsPerPage() const  { return mQuadsPerPage; }
 			UINT32 getWidth() const;
@@ -110,7 +110,7 @@ namespace CamelotFramework
 			friend class TextUtility;
 
 			std::vector<UINT32> mQuadsPerPage;
-			std::vector<TextLine*> mLines;
+			std::vector<TextLine> mLines;
 			std::vector<HTexture> mTexturePages;
 		};
 

+ 32 - 42
CamelotCore/Source/CmTextUtility.cpp

@@ -80,18 +80,14 @@ namespace CamelotFramework
 
 	TextUtility::TextLine::~TextLine()
 	{
-		for(auto iter = mWords.begin(); iter != mWords.end(); ++iter)
-			CM_DELETE(*iter, TextWord, ScratchAlloc);
 	}
 
 	void TextUtility::TextLine::add(const CHAR_DESC& charDesc)
 	{
 		if(mLastWord == nullptr)
 		{
-			TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(false);
-			mLastWord = newWord;
-
-			mWords.push_back(mLastWord);
+			mWords.push_back(TextWord(false));
+			mLastWord = &mWords.back();
 
 			mLastWord->addChar(charDesc);
 		}
@@ -99,10 +95,8 @@ namespace CamelotFramework
 		{
 			if(mLastWord->isSpacer())
 			{
-				TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(false);
-				mLastWord = newWord;
-
-				mWords.push_back(mLastWord);
+				mWords.push_back(TextWord(false));
+				mLastWord = &mWords.back();
 			}
 
 			mLastWord->addChar(charDesc);
@@ -115,19 +109,15 @@ namespace CamelotFramework
 	{
 		if(mLastWord == nullptr)
 		{
-			TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(true);
-			mLastWord = newWord;
-
-			mWords.push_back(mLastWord);
+			mWords.push_back(TextWord(true));
+			mLastWord = &mWords.back();
 
 			mLastWord->addSpace(mSpaceWidth);
 		}
 		else
 		{
-			TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(true); // Each space is counted as its own word, to make certain operations easier
-			mLastWord = newWord;
-
-			mWords.push_back(mLastWord);
+			mWords.push_back(TextWord(true)); // Each space is counted as its own word, to make certain operations easier
+			mLastWord = &mWords.back();
 
 			mLastWord->addSpace(mSpaceWidth);
 		}
@@ -135,24 +125,24 @@ namespace CamelotFramework
 		calculateBounds();
 	}
 
-	void TextUtility::TextLine::addWord(TextWord* word)
+	void TextUtility::TextLine::addWord(const TextWord& word)
 	{
 		mWords.push_back(word);
-		mLastWord = word;
+		mLastWord = &mWords.back();
 
 		calculateBounds();
 	}
 
-	TextUtility::TextWord* TextUtility::TextLine::removeLastWord()
+	TextUtility::TextWord TextUtility::TextLine::removeLastWord()
 	{
 		if(mWords.size() == 0)
 			return nullptr;
 
-		TextWord* word = mWords[mWords.size() - 1];
+		TextWord word = mWords[mWords.size() - 1];
 		mWords.erase(mWords.end() - 1);
 
 		if(mWords.size() > 0)
-			mLastWord = mWords[mWords.size() - 1];
+			mLastWord = &mWords[mWords.size() - 1];
 		else
 			mLastWord = nullptr;
 
@@ -166,9 +156,9 @@ namespace CamelotFramework
 		std::vector<UINT32> quadsPerPage;
 		for(auto wordIter = mWords.begin(); wordIter != mWords.end(); ++wordIter)
 		{
-			if(!(*wordIter)->isSpacer())
+			if(!wordIter->isSpacer())
 			{
-				const vector<CHAR_DESC>::type& chars = (*wordIter)->getChars();
+				const vector<CHAR_DESC>::type& chars = wordIter->getChars();
 				UINT32 kerning = 0;
 				for(auto charIter = chars.begin(); charIter != chars.end(); ++charIter)
 				{
@@ -190,13 +180,13 @@ namespace CamelotFramework
 		UINT32 penX = 0;
 		for(auto wordIter = mWords.begin(); wordIter != mWords.end(); ++wordIter)
 		{
-			if((*wordIter)->isSpacer())
+			if(wordIter->isSpacer())
 			{
 				penX += mSpaceWidth;
 			}
 			else
 			{
-				const vector<CHAR_DESC>::type& chars = (*wordIter)->getChars();
+				const vector<CHAR_DESC>::type& chars = wordIter->getChars();
 				UINT32 kerning = 0;
 				for(auto charIter = chars.begin(); charIter != chars.end(); ++charIter)
 				{
@@ -259,15 +249,13 @@ namespace CamelotFramework
 		mHeight = 0;
 		for(auto iter = mWords.begin(); iter != mWords.end(); ++iter)
 		{
-			mWidth += (*iter)->getWidth();
-			mHeight = std::max(mHeight, (*iter)->getHeight());
+			mWidth += iter->getWidth();
+			mHeight = std::max(mHeight, iter->getHeight());
 		}
 	}
 
 	TextUtility::TextData::~TextData()
 	{
-		for(size_t i = 0; i < mLines.size(); i++)
-			CM_DELETE(mLines[i], TextLine, ScratchAlloc);
 	}
 
 	std::shared_ptr<TextUtility::TextData> TextUtility::getTextData(const String& text, const HFont& font, UINT32 fontSize, UINT32 width, UINT32 height, bool wordWrap)
@@ -291,8 +279,8 @@ namespace CamelotFramework
 		bool widthIsLimited = width > 0;
 
 		std::shared_ptr<TextUtility::TextData> textData(CM_NEW(TextData, PoolAlloc) TextData(), &MemAllocDeleter<TextData, PoolAlloc>::deleter);
-		TextLine* curLine = CM_NEW(TextLine, ScratchAlloc) TextLine(fontData->fontDesc.baselineOffset, fontData->fontDesc.lineHeight, fontData->fontDesc.spaceWidth);
-		textData->mLines.push_back(curLine);
+		textData->mLines.push_back(TextLine(fontData->fontDesc.baselineOffset, fontData->fontDesc.lineHeight, fontData->fontDesc.spaceWidth));
+		TextLine* curLine = &textData->mLines.back();
 
 		UINT32 curHeight = fontData->fontDesc.lineHeight;
 		UINT32 charIdx = 0;
@@ -307,8 +295,9 @@ namespace CamelotFramework
 				if(heightIsLimited && (curHeight + fontData->fontDesc.lineHeight * 2) > height)
 					break; // Max height reached
 
-				curLine = CM_NEW(TextLine, ScratchAlloc) TextLine(fontData->fontDesc.baselineOffset, fontData->fontDesc.lineHeight, fontData->fontDesc.spaceWidth);
-				textData->mLines.push_back(curLine);
+				textData->mLines.push_back(TextLine(fontData->fontDesc.baselineOffset, fontData->fontDesc.lineHeight, fontData->fontDesc.spaceWidth));
+				curLine = &textData->mLines.back();
+
 				curHeight += fontData->fontDesc.lineHeight;
 
 				charIdx++;
@@ -340,19 +329,20 @@ namespace CamelotFramework
 			{
 				if(wordWrap)
 				{
-					TextWord* lastWord = curLine->removeLastWord();
-					if(lastWord->isSpacer())
+					TextWord lastWord = curLine->removeLastWord();
+					if(lastWord.isSpacer())
 						curLine->addWord(lastWord); // Spaces can stay on previous line even if they don't technically fit
 
 					// No more lines fit vertically so we're done
 					if(heightIsLimited && curHeight > height)
 						break;
 
-					curLine = CM_NEW(TextLine, ScratchAlloc) TextLine(fontData->fontDesc.baselineOffset, fontData->fontDesc.lineHeight, fontData->fontDesc.spaceWidth);
-					textData->mLines.push_back(curLine);
+					textData->mLines.push_back(TextLine(fontData->fontDesc.baselineOffset, fontData->fontDesc.lineHeight, fontData->fontDesc.spaceWidth));
+					curLine = &textData->mLines.back();
+
 					curHeight += fontData->fontDesc.lineHeight;
 
-					if(!lastWord->isSpacer())
+					if(!lastWord.isSpacer())
 						curLine->addWord(lastWord);
 				}
 				else
@@ -373,7 +363,7 @@ namespace CamelotFramework
 		UINT32 width = 0;
 
 		for(auto& line : mLines)
-			width = std::max(width, line->getWidth());
+			width = std::max(width, line.getWidth());
 
 		return width;
 	}
@@ -383,7 +373,7 @@ namespace CamelotFramework
 		UINT32 height = 0;
 
 		for(auto& line : mLines)
-			height += line->getHeight();
+			height += line.getHeight();
 
 		return height;
 	}

+ 0 - 1
CamelotUtility/CamelotUtility.vcxproj

@@ -189,7 +189,6 @@
     <ClInclude Include="Include\CmLog.h" />
     <ClInclude Include="Include\CmManagedDataBlock.h" />
     <ClInclude Include="Include\CmMathAsm.h" />
-    <ClInclude Include="Include\CmMemBlockPool.h" />
     <ClInclude Include="Include\CmMemoryAllocator.h" />
     <ClInclude Include="Include\CmModule.h" />
     <ClInclude Include="Include\CmORect.h" />

+ 0 - 3
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -219,9 +219,6 @@
     <ClInclude Include="Include\CmMemStack.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="Include\CmMemBlockPool.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">

+ 0 - 194
CamelotUtility/Include/CmMemBlockPool.h

@@ -1,194 +0,0 @@
-#pragma once
-
-#include <vector>
-#include <cmath>
-
-namespace CamelotFramework
-{
-	/**
-	 * @brief	Memory block pool.
-	 *
-	 * @tparam	PageSizePow2	2^PageSizePow2 is the size of one page in the pool. This size divided by number of blocks per chunk
-	 * 							determines the maximum size you can allocate in the pool. Larger allocations will use a general allocator.
-	 * @tparam	BlocksPerChunkPow2 Pages are split into chunks and chunks are split into smaller chunks based on this value.
-	 * 							   Higher values generally guarantee less allocations and better performance, but potentially 
-	 * 							   more wasted memory. Actual blocks per chunk is calculated by 2^BlocksPerChunkPow2.
-	 * 							   Has to be equal or less than PageSizePow2. Must be equal or less than 8.
-	 * 							   (e.g. 0 means 1 block per chunk, 1 means 2 blocks per chunk, etc.)
-	 */
-	template <int PageSizePow2 = 20, int BlocksPerChunkPow2 = 5>
-	class MemBlockPool
-	{
-		struct MemChunk
-		{
-			MemChunk()
-				:firstFreeBlock(0), numAvailableBlocks(0), data(nullptr)
-			{ }
-
-			void init(unsigned char* _data, unsigned int blockSize, unsigned char numBlocks)
-			{
-				data = _data;
-				numAvailableBlocks = numBlocks;
-				firstFreeBlock = 0;
-
-				unsigned char* dataPtr = data;
-				for(unsigned char i = 0; i < numBlocks; ++i)
-				{
-					*dataPtr = i;
-					dataPtr += blockSize;
-				}
-			}
-
-			void release()
-			{
-
-			}
-
-			void* alloc(unsigned int blockSize)
-			{
-				if(numAvailableBlocks == 0) return nullptr;
-
-				unsigned char* result = data + (firstFreeBlock * blockSize);
-				firstFreeBlock = *result;
-
-				--numAvailableBlocks;
-				return result;
-			}
-
-			void dealloc(void* dataToRls, unsigned int blockSize)
-			{
-				unsigned char* toRelease = static_cast<unsigned char*>(dataToRls);
-				*toRelease = firstFreeBlock;
-				firstFreeBlock = (toRelease - data) / blockSize;
-
-				++numAvailableBlocks;
-			}
-
-			unsigned char* data;
-			unsigned char firstFreeBlock;
-			unsigned char numAvailableBlocks;
-		};
-
-		struct MemPool
-		{
-			std::vector<MemChunk> mChunks;
-			unsigned int mBlockSize;
-			MemChunk* mAllocChunk;
-			MemChunk* mDeallocChunk;
-		};
-
-	public:
-		MemBlockPool()
-		{
-			unsigned int blockSize = 1 << BlocksPerChunkPow2;
-			mNumPools = PageSizePow2 - BlocksPerChunkPow2;
-			for(int i = 0; i < mNumPools + 1; i++)
-			{
-				mPools[i].mBlockSize = blockSize;
-				mPools[i].mAllocChunk = nullptr;
-				mPools[i].mDeallocChunk = nullptr;
-				blockSize = blockSize << 1;
-			}
-
-			mBlocksPerChunk = 1;
-			for(int i = 0; i < BlocksPerChunkPow2; i++)
-				mBlocksPerChunk <<= 1;
-		}
-
-		~MemBlockPool()
-		{
-			// TODO - Handle release
-
-			//for(auto iter = mChunks.begin(); iter != mChunks.end(); ++iter)
-			//	iter->release();
-		}
-
-		void* alloc(unsigned int size)
-		{
-			unsigned int poolIdx = sizeToPool(size) - BlocksPerChunkPow2;
-
-			if(poolIdx >= mNumPools) 
-				return CM_NEW_BYTES(size, GenAlloc);
-
-			MemPool& pool = mPools[poolIdx];
-			if(pool.mAllocChunk == nullptr || pool.mAllocChunk->numAvailableBlocks == 0)
-			{
-				for(auto iter = pool.mChunks.begin();; ++iter)
-				{
-					if(iter == pool.mChunks.end())
-					{
-						pool.mChunks.reserve(pool.mChunks.size() + 1);
-
-						MemChunk newChunk;
-						newChunk.init((unsigned char*)alloc(pool.mBlockSize * mBlocksPerChunk), pool.mBlockSize, mBlocksPerChunk);
-
-						pool.mChunks.push_back(newChunk);
-						pool.mAllocChunk = &pool.mChunks.back();
-						pool.mDeallocChunk = &pool.mChunks.back();
-						break;
-					}
-
-					if(iter->numAvailableBlocks > 0)
-					{
-						pool.mAllocChunk = &*iter;
-						break;
-					}
-				}
-			}
-
-			return pool.mAllocChunk->alloc(pool.mBlockSize);
-		}
-
-		void dealloc(void* dataToRls, unsigned int size)
-		{
-			unsigned int poolIdx = sizeToPool(size) - BlocksPerChunkPow2;
-
-			if(poolIdx >= mNumPools) 
-				return CM_DELETE_BYTES(dataToRls, GenAlloc);
-
-			MemPool& pool = mPools[poolIdx];
-			if(pool.mDeallocChunk == nullptr || dataToRls < pool.mDeallocChunk->data || dataToRls >= (pool.mDeallocChunk->data + pool.mBlockSize * mBlocksPerChunk))
-			{
-				for(auto iter = pool.mChunks.begin();; ++iter)
-				{
-					assert(iter != pool.mChunks.end()); // Trying to dealloc memory that wasn't allocated by this allocator
-
-					if(dataToRls >= iter->data && dataToRls < (iter->data + pool.mBlockSize * mBlocksPerChunk))
-					{
-						pool.mDeallocChunk = &*iter;
-						break;
-					}
-				}
-			}
-		
-			pool.mDeallocChunk->dealloc(dataToRls, pool.mBlockSize);
-
-			// If chunk is empty, release it (either to a higher level chunk to re-use, or to the OS if the chunk is highest level)
-			if(pool.mDeallocChunk->numAvailableBlocks == mBlocksPerChunk) // Chunk is completely empty
-			{
-				auto findIter = std::find(pool.mChunks.begin(), pool.mChunks.end(), pool.mDeallocChunk);
-				pool.mChunks.erase(findIter);
-
-				dealloc(pool.mDeallocChunk->data, pool.mBlockSize * mBlocksPerChunk);
-
-				pool.mDeallocChunk = nullptr;
-			}
-		}
-
-	private:
-		MemPool mPools[PageSizePow2 + 1];
-		unsigned int mBlocksPerChunk;
-		unsigned int mNumPools;
-
-		unsigned int sizeToPool(unsigned int size)
-		{
-			// TODO - Size cannot be zero
-
-			unsigned int targetlevel = 0;
-			while (size >>= 1) // I can speed this up using a BSR instruction, in case compiler doesn't already do it
-				++targetlevel;
-
-			return targetlevel;
-		}
-	};
-}