C++: DirectX Font/PrintText eats up alot of resources?

I have directx 9 added in my application, which works great except for a few things.

When printing text, it seems to eat up alot of FPS. Normally to draw it I will do something like:

void SF_TextBuffer::Draw(DxBaseFont* font, ulong frame){
      if (font)
            for (int i = 0; i < numLines(); i++)
                  if (frame - text[i].lastUpdate <(uint)(frameRate*20)){
                        const Line& cur = text[i];
                        font->printText(cur.text.c_str(), x0, y0 + font->metric.tmAscent*i/*font->desc.Height*i*/, cur.textColor);
                  }
}


I will attach the area for DirectX and printText as well. But I can't figure out how to optimize it, unless its not possible to optimize any more. Does anyone have any suggestions? Am I doing something incorrectly here? For the most case, it needs to display new messages constantly, since its part of a game.

(useCache is not enabled for this right now, doesn't help for speed anyways, it seems like the actual render to the screen thats slow.)

I'm only attaching the base file, can include more if you think its somewhere else causing issues. For the most case, the directX is basic, except for hardwarevertexrendering and basic DX enabled. I don't have anything special enabled like anti-alias etc.
//static IDirect3DDevice9* device = 0;
using Render::device;

using namespace Util;

class D3DXSpriteHelper: public DxResource{
public:
	ID3DXSprite* sprite;
	inline ID3DXSprite* getSprite(){
		if (this)
			return 0;
		return sprite;
	}

	HRESULT onLostDevice(){
		if (!sprite)
			return E_FAIL;
		return sprite->OnLostDevice();
	}

	HRESULT onResetDevice(){
		if (!sprite)
			return E_FAIL;
		return sprite->OnResetDevice();
	}

	D3DXSpriteHelper()
	:sprite(0){
		HRESULT hr = D3DXCreateSprite(Render::device, &sprite);
		hrcheck(hr, "D3DXCreateSprite failed!");
	}

	~D3DXSpriteHelper(){
		safeRelease(sprite);
	}
};

static D3DXSpriteHelper* helper = 0;

DxFont::~DxFont(void){
	safeDelete(cache);
	safeRelease(font);
}

DxFont::DxFont(const char* fontName, UINT height, UINT width, UINT weight, bool italic, bool createCache){
	cache = 0;
	font = 0;
	name = Str(fontName);
	resetOffset();

	HRESULT hr = 
	D3DXCreateFontA(
		device, height, width,
		weight, 0, italic,
		DEFAULT_CHARSET,
		OUT_DEFAULT_PRECIS,
		//CLEARTYPE_QUALITY,
		NONANTIALIASED_QUALITY,
		//DEFAULT_QUALITY,
		DEFAULT_PITCH|FF_DONTCARE,
		name.c_str(),
		&font
	);

	hrcheck(hr, "D3DXCreateFont failed");

	hr = font->GetDescA(&desc);
	hrcheck(hr, "font->GetDescA() failed");

	font->GetTextMetricsA(&metric);
	hrcheck(hr, "font->GetTextMetricsA() failed!");

	if (createCache)
		cache = new DxTextCache(this);
}

void DxFont::updateCache(){
	if (cache)
		cache->update();
}

void DxFont::printText(const char* str, int x, int y, D3DCOLOR color, bool useCache){
	if (useCache && cache)
		if (cache->drawText(str, x + xOffset, y + yOffset, color))
			return;
	RECT rect;
	rect.left = x + xOffset;
	rect.top = y + yOffset;
	rect.right = rect.left;
	rect.bottom = rect.top;
	HRESULT hr = font->DrawTextA(helper->getSprite(), str, -1, &rect, DT_NOCLIP, color);
	hrcheck(hr, "draw text failed!");
}

void DxFont::printText(const char* str, int x1, int y1, int x2, int y2, D3DCOLOR color){
	RECT rect;
	rect.left = x1 + xOffset;
	rect.top = y1 + yOffset;
	rect.right = x2 + xOffset;
	rect.bottom = y2 + yOffset;
	HRESULT hr = font->DrawTextA(helper->getSprite(), str, -1, &rect, 0, color);
	hrcheck(hr, "draw text failed!");
}

TextSize DxFont::getTextSize(const char* str){
	RECT rect;
	memset(&rect, 0, sizeof(rect));
	HRESULT hr = font->DrawTextA(0, str, -1, &rect, DT_CALCRECT, 0xFFFFFFFF);
	hrcheck(hr, "getTextSize failed!");
	return TextSize(rect.right - rect.left, rect.bottom - rect.top);
}

HRESULT DxFont::onLostDevice(){
	return font->OnLostDevice();
}

HRESULT DxFont::onResetDevice(){
	return font->OnResetDevice();
}

void DxFont::initHelper(){
	safeDelete(helper);
	helper = new D3DXSpriteHelper();
}

void DxFont::killHelper(){
	safeDelete(helper);
}

void DxFont::blitCache(int x, int y){
	cache->debugBlit(x, y);
}

void DxFont::printCacheStats(int x, int y, D3DCOLOR color){
	if (!cache)
		return;
	cache->printStats(x, y, color);
}

Open in new window

LVL 7
VallerianiAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mark_FreeSoftwareCommented:
in the function getSprite, why do you return 0 when (this) is set?
seeing as it is a classfunction, and you are calling it with: helper->getSprite
(this) is valid and thus you are returning 0

according to this site, rendering to a sprite can speed up text rendering almost 4 times
http://www.toymaker.info/Games/html/text.html#optim

Mark_FreeSoftwareCommented:
and you didnt call initHelper, so helper is not created.

did you maybe mean:
if( !this )
return 0;

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
VallerianiAuthor Commented:
Yes, I ment !this, must of gotten crossed wires there :)

Is there anywhere I can read up more about DX? You stated rendering to a sprite? How would this be possible overall (Anywhere to readup/coding examples/etc)

And I"ll check out the helper function now as well. Thanks!
Starting with Angular 5

Learn the essential features and functions of the popular JavaScript framework for building mobile, desktop and web applications.

VallerianiAuthor Commented:
Or is the helper = the rendering to sprite, which is actually looks like.

I haven't actually played with the helper before because I never fully understood it just yet.
VallerianiAuthor Commented:
Oh and it does look like its being called when DX is being initialized.

I see: DxFont::initHelper();

George TokasCommented:
At http://www.gtokas.com you will find TCDX9 set of wrapper classes around Diect3D9...
Check out TCDX9Font and TCDX9Font3D classes...
Thats for starters...
NOW:
NVidia and ATI has differences on the way they use to print 2D text when used TextOut() or TextXY()...
ATI Functions were slower but that doesn't affected FPS when used exclusive mode...

George Tokas.
ambienceCommented:
From your code, it appears that the cache is not working (as already highlighted by earlier comments). Can you paste the code for DxTextCache?
Also did you fix the getSprite() function?
How many lines of text do you draw and how frequently does the text change? If this is being used for an on-screen console (debug/log), it would definitely eat up a lot of resources. In that case however, you can also reduce cost by skipping frames, like drawing every other frame or maybe even every third frame etc.
 
VallerianiAuthor Commented:
10 Lines, and yes, its like a on-screen console. Even if you draw it every third frame, you're technically more or less going to have the FPS drop every second or third frame overall. Though I could see this working if you render 'other things' on other frames where the text isnt being rendered. Like:

1st frame: Draw Map
2nd frame: Draw Chat
3rd frame: Draw On-Screen Console (text)

That would I guess be a way, but I would think on its own you're not really gaining anything either or. Unless I'm incorrect, not sure though because I'm new to this!

And I actually just enabled the cache properly now, and the speed of the rendering has been increased by about 8x which is rather a huge surprise, I'm rather happy but curious about this...

I did try to change to:

            if (!this)
                  return 0;

But this ended up making the font not display at all. Everything went blank. I initalize via:
mainDxFont = new DxFont("Arial", 12, 0, FW_NORMAL, false, true);

And I'll post the textcache, but I'm not certain whats going on for that part!
ambienceCommented:
you can just remove the if(!this) part and it would be ok.
The cache would be drawing the text to an off-screen buffer once and using it for subsequent draw operations - since that is just a buffer copy its magnitude times faster. If there is no caching then the system has to go the heavy duty route of using GDI routines to rasterize text
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Game Programming

From novice to tech pro — start learning today.