People with DirectX knowledge wanted! (1 Viewer)

V

Vic

Guest
I took a look at the DirectX code and the FontEngine yesterday. One thing that struck me was the way that text is drawn to screen. Currently you draw all strings on screen using two triangles and four vertices per letter. This seems to be done every frame.

Wouldn't it be better to render the text once to a texture and then simply use that texture from then on to display the text using just two triangles? The same would be applied to all controls, i.e. render them once to a texture and then use that one until the control changes appearance in one way or another. To reduce the amount of texture switching, all controls could be drawn to the same offscreen surface just on different locations (a little bit tricky, but can be done).

Additionally, each control could have a matrix transformation attached to it to translate and/or rotate it without needing to update the vertex buffer. This way you do not need to lock and update the vertex buffer at all. however, I'm not sure if this would be better than locking and updating the vertices since the amount of vertices is quite small for each control.

If you want, I could take a closer look and see if I could implement some of this...
 

emp3r0r

Portal Member
October 6, 2004
24
0
0% cpu usage 30+fps 100+ objects using sprites

I created a prototype using sprites to batch the drawing of textures and fonts on the screen and I was able to draw lots of stuff on screen with barely any cpu usage. I called render 30 times a second. Here is what I did:

used 1 texture for background
used 1 texture for controls
used 1 font for per font style (I had 4 font styles)
used 1 sprite for rendering
reused above sprite to draw text

Basically all drawing occured using one batched sprite. CPU usage remained very low (<1%), even when drawing lots of objects and throwing lots of events like the mousemove event. I tested it on a 2ghz cpu and a 32meg Radeon VE card.

Lessons learned:
1) Keep number of textures to load very low. Don't have 3 textures for a button, rather combine all the textures into one larger texture. For example, all the common controls like, button, checkbox, scrollbar, listcontrol, spincontrol, etc should be in one texture.

2) Keep the texture size as small as possible, if you combine textures, don't leave any room between those textures.

3) Remember the power of 2 rule for texture dimensions.

4) Larger render area means larger textures (ie: background texture) so when the textures loaded exceeds video memory, expect huge increases in CPU usage since it must pull texture data from system memory. For example, since my video card only has 32megs of ram, I had to be very thrifty with the textures I loaded.

Interesting observations:
1) I was able to render MediaPortal like graphics on an old graphics card.
2) Drawing 1000+ objects at 30fps resulted in ~70% cpu usage.
3) Drawing 500+ objects at 60fps resulted in ~70% cpu usage.
4) Drawing 100+ objects at 120fps resulted in ~2.5% cpu usage with spikes of 5%
5) All code was C#
 

emp3r0r

Portal Member
October 6, 2004
24
0
render code

Code:
/// <summary>
/// This is the main program loop, where it constantly renders to screen
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) 
{	
	//check enough time has passed to render
	deltaTime = hrt.ElapsedTime;
	if (deltaTime > MAX_FRAME_RATE)
	{
		deltaTime = 0.0f;
		//dont render faster than max frame rate
		this.Invalidate();
	}

	//draw screen
	Renderer.Render(screen);

	//force redraw
	this.Invalidate();
}
 

koniosis

Portal Member
January 21, 2005
7
0
frodo said:
Ok, here's what we do now:
1. I create 1 big vertexbuffer per texture (lets say a button)
2. I update the vertex buffer with all positions of all buttons onscreen
3. I render the screen (no updates/locks here)
4. goto 3

Ok so I'm back after being dragged away for a long time. If you're still doing what you quoted in this post you're doing it wrong. Like I said you don't need to lock the vertex buffers, you can do a transformation.

Now if you're using Sprites you can do something along these lines:

Code:
public void Draw(Sprite sprite, Texture texture)
{
    sprite.Transform = 
        Matrix.RotationZ(m_Rotation) *
        Matrix.Translation(m_Center) *
        Matrix.Scaling(m_Scale);

    sprite.Draw(texture, m_Rectangle, m_Center, m_Position, m_Color);
}

Assuming you've stored the rotation, centre location and scale of the texture as well as it's colour overlay you want to draw within the class that contains the Draw function. e.g.:

Code:
protected Vector3 m_Position = new Vector3(0, 0, 0);
protected Vector3 m_Center = new Vector3(0, 0, 0);
protected Vector3 m_Scale = new Vector3(1, 1, 1);
protected Color m_Color = Color.FromArgb(255,255,255,255);

Using 1 big vertex buffer might work but its the same issue, locking the vertex buffer is costly and the larger it is the worse it is, so you're just moving the problem from lots of small locks to one large slow lock.

I don't remember exactly how much detail I went into previously about this but you should be queueing all your sprite drawing operations up and drawing them all at the same time using a single sprite object.

E.g each control (button, check box etc.) has a Draw function that takes some Queue object that has an .Add method which takes say an IDrawable interface which your controls implment that exposes a DrawMe method or something. Then when you ask a button to Draw() itself it simply adds itself to the queue as an IDrawable object. Now when you are ready to render the screen you loop through the Queue and call .DrawMe on each object with code similar to:

Code:
public void Draw(float elapsedTime)
using (Sprite sprite = new Sprite(m_Device))
{
    sprite.Begin(SpriteFlags.AlphaBlend);

    for(int i = 0; i < m_SpriteQueue.Count; i++)
    {
        m_SpriteQueue[i].Update(elapsedTime);
        m_SpriteQueue[i].Draw(sprite);
    }

    sprite.End();
}

m_SpriteQueue.Clear();
}

Note that I've also added an Update method to the IDrawable interface so that I can let my object update themselves by the elapsed time since the last frame (allowing for animations etc). I then ask the object to draw itself using the specified sprite (note, i use the same sprite to render all controls).

Hope that's some help,

Koni
 

diehard2

Retired Team Member
  • Premium Supporter
  • April 22, 2006
    518
    28
    Chicago
    Home Country
    United States of America United States of America
    LordMessi said:
    We still need people with DirectX knowledge - mostly DirectShow.

    Anyone ??

    Hi, I have a fairly extensive knowledge of DirectShow. I've implemented an image analysis filter and a deinterlacing filter based on KernelDeint from AviSynth. I've also authored a DV/Fileplayer to use these filters. I unfortunately don't read C#, but I would be willing to take a look at sections that need work.

    ~Steve

    P.S. Before taking a look at the MP sources, I was unaware that one was even able to use C# with directshow. Did the MP team implement the interfaces themselves?
     

    Geon106

    Portal Pro
    June 23, 2006
    164
    0
    35
    Kent, England
    Home Country
    United Kingdom United Kingdom
    I find MP is slowest when switched from one menu to another esp those with thumbnails, so maybe MP should use lower colour deph thumbnails and turn pictures that are being used as thumbnails into a lower resolution, like 150x150 max?
     

    Users who are viewing this thread

    Top Bottom