GDI Still slow?

Started by
4 comments, last by Fiddler 17 years, 11 months ago
I work for a non-game company, and mainly work in visualization, often in the from ox xy/xyz plots. I was going to be refactoring some code that allowed our 2-D plot library to use DirectX by way of Surfaces and DC's to surfaces, when I decided to run a little test to see what kind of benefit would be gained. I don't know why, I ran a similar test last year, and found for small amounts of points, GDI and D3D were neck and neck, but as the number of points jumped up, to say 1,000,000 D3D left the GDI in its dust. This test, however, was using the D3DPT_LINESTRIP primitive type. This unfortunatly has some annoying limitations like line width...I was unconvinced at the speed boost that using DC's to surfaces would provide, so I wrote a pretty simple test window class. The window really did 3 main things. First, overload Create, so that once the window is created, it would load up Direct3D and I also did a test with DirectDraw (2 seperate classes). Second, it overloaded the GetDC, and ReleaseDC methods, just for simplicities sake. Last, it provided an OnPaint function which draws n number of random lines using the DC. Once with the GDI, and would time it, once with either D3D or DDraw. What I found was that the GDI was not all that much slower. DDraw was the slowest which was a surprise, now, it may be that if I rendered to a backbuffer then flipped, it would be right there with D3D, but I don't know, maybe I'll try it for kicks :) The GDI came in second place, and you can see, not by much...D3D was on top. For 1,000,000 lines, here was the timing result. Obviously, ignore the cycle count since it took more than 1 second... Took 4469ms and 12485835131 cycles using the GDI... Took 3641ms and 10172788192 cycles using Direct3D... Took 4265ms and 11892894587 cycles using the GDI... Took 3735ms and 10436728106 cycles using Direct3D... Took 4266ms and 11879211442 cycles using the GDI... Took 3671ms and 10285906211 cycles using Direct3D... Took 4250ms and 11885368320 cycles using the GDI... Took 3703ms and 10321315389 cycles using Direct3D... Took 4750ms and 13273147244 cycles using the GDI... Took 3688ms and 10302188911 cycles using Direct3D... Took 4265ms and 11899816929 cycles using the GDI... Took 3688ms and 10273496009 cycles using Direct3D... Took 4250ms and 11899397314 cycles using the GDI... Took 3672ms and 10264237277 cycles using Direct3D... Took 4266ms and 11892780977 cycles using the GDI... Took 3688ms and 10324699693 cycles using Direct3D... Took 4828ms and 13493153772 cycles using the GDI... Took 3625ms and 10165319388 cycles using Direct3D... Took 4250ms and 11889903830 cycles using the GDI... Took 3718ms and 10373259127 cycles using Direct3D... The GDI here took on average 4385.9 ms to draw 1,000,000 lines. Direct3D took on average 3682.9ms to draw 1,000,000 lines. A difference of 703ms on average or 16%. This is not nearly the speed boost I expected. I figured well, maybe it is because I have to get a backbuffer, write to it, and flip, instead of getting the front buffer once, writing to it, and being done with it. So I decided to try DirectDraw which lets you get the primary surface. Results follow... And the results with DirectDraw... Took 4266ms and 11923468760 cycles using the GDI... Took 4656ms and 13018767265 cycles using DirectDraw... Took 4250ms and 11866329972 cycles using the GDI... Took 4656ms and 12995605091 cycles using DirectDraw... Took 4250ms and 11894626310 cycles using the GDI... Took 4656ms and 12977429290 cycles using DirectDraw... Took 4265ms and 11883850174 cycles using the GDI... Took 4641ms and 12974699367 cycles using DirectDraw... Took 4250ms and 11864043100 cycles using the GDI... Took 4641ms and 12977754055 cycles using DirectDraw... Took 4250ms and 11893169918 cycles using the GDI... Took 4625ms and 12957825587 cycles using DirectDraw... Took 4250ms and 11866776159 cycles using the GDI... Took 4656ms and 13001120790 cycles using DirectDraw... Took 4641ms and 12932629262 cycles using the GDI... Took 4594ms and 12821419268 cycles using DirectDraw... Took 4797ms and 13373353329 cycles using the GDI... Took 4594ms and 12834056193 cycles using DirectDraw... Took 4735ms and 13199476143 cycles using the GDI... Took 4578ms and 12823452481 cycles using DirectDraw... I wont bother averaging it out, DirectDraw was obviously slower, and therefore won't even be considered. Again, maybe it is faster to just use the backbuffer and page flip, but thats what I have going on with Direct3D....I may satisfy my curiosity later and try that. Anyone else have any similar experience? I have read that blitting it accellerated, but for the most part, that isn't what I am doing here. Its simply drawing points, markers and lines on a surface (thats all that plotting is) Sure I could draw to a surface, then blit to the main surface, but that would just be the same slow operations followed by a faster operation, obviously that won't change anything. At some point when I have more time I'll implement something that has variable line widths, marker types etc all using triangles and using 3D accelleration, since I am convinced that will be faster, the D3DPT_LINELIST certainly was :) Edit: Bah, now I remember why there is no page flipping...after going to midify it and satisfy my curiosity, I got the No Exclusive Mode error, well duh, this can't be a full screen app....then it all came back to me :) So I am going to assume DDraw was slower since it had to be synchronized, much like the GDI, but D3D writes to an exclusive buffer, then can just flip, taking some waiting time out of the equation. Still 16% is hardly enough to justify reworking everything... [Edited by - Corryl on May 17, 2006 2:23:29 PM]
Advertisement
How did you draw your GDI lines? MoveTo/LineTo or PolyPolyLine? If the former you can get a boost by converting to the latter. Although it sounds like things are already fast enough just doing it the easy way.
-Mike
GDI performance varies wildly from system to system and can be effected by user configuration choices

In addition, any hardware acceleration that GDI uses can be effected by conditions external to your code (such as other processes which are maintaining a lot of gdi resources)

Well, its just doing a moveto-lineto-lineto...etc. I didn't write that whole section, nor did I write the initial directx conversion. I was asked to refactor some of it, but I figured I'd check to see if that was really worthwhile, and ran the tests...by those numbers, I'd just stick to the GDI and maybe as you suggessted switch to a polyline.

Figure though this will always be running on a P4 2.8+, with a decent video card, since for the most part, you're not going to get much worse than something Geforce4 level these days. My development/test box is a P4 2.8 Prescott, with a Radeon X300...

As far as other applications using GDI resources, the software we write here is meant to be the only application running, and the only purpose for the computer. It is always a front end for some custom piece of hardware generating data at ridiculous rates. The front ends generally configure the hardware, recieve/log the data, and maybe plot some of the data. Other applications will slow down the ability of the software to recieve the data, and generally slow everything down, which is why we say it really should be the only thing running.

Anyways, thanks for the input
Quote:Original post by Anon Mike
How did you draw your GDI lines?


I would say "how do you draw your D3D or DDraw lines ?". These figures looks suspiciously slow IMHO. Anon Mike suggested you to draw lines using PolyLine, I suggest you to use a similar approach using D3D (instead of drawing only one line at a time, draw as many as you want).

BTW, you can 'simulate' the drawing of thick lines by drawing polygons instead of lines (the good thing is that you'll be able to have FSAA if needed).

Regards,
Wild guess: you are generating one line at a time using D3D, meaning you are extremely batch-limited. If this is the case try creating vertex buffers of a decent size (4K-16K is optimal AFAIK) and filling them before drawing.

If this is not a choice, try using OpenGL, since its immediate mode has a lot less overhead than D3D (if you try to emulate immediate mode with D3D that is).

As I said, this is a wild guess. I do not know how you are generating the line strips, but you should be able to get at least 10 _million_ lines a second (my Radeon 9600 Pro can process 12M transformed, lit and textured triangles with ease - and can probably do a lot more with careful programming).

[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]

This topic is closed to new replies.

Advertisement