|
I'm writing a game using C++/CLI (.NET 2.0), taking full advantage of .NET framework for the ease of writing dialog boxes, menus, etc, but keeping my core logic and OpenGL code in "native" C++. Since my main window is a .NET window, I am using a Timer control to trigger the rendering cycle. Since I want to draw as fast as possible, the timer interval is set to 1 ms.
The test scene I'm rendering contains a measely 10,000 triangles. My framerate is a poor 64fps -- running the executable directly (running in the IDE drops my frames to 5fps). I don't know a lot about graphics cards, but I do know their performance is sometimes measured in millions of triangle per sec. If you do the math, 10k triangles * 64fps = 640,000 triangles per second. NOT GOOD.
I do most of my development on a notebook that has a screen refresh rate of 60Hz. I thought that might be the problem, so I switched over to my tower, which is running an Nvidia GeForce 5900XT and a refresh rate of 75Hz. Guess what? I still get the 64fps rendering rate.
Is this the best I can expect from a .NET-encompassed application? Would switching back to an older technology like MFC or even plain old Win32 programming increase my framerate? I do have a good C++ background with pointers and all that stuff, so I'm not afraid to roll up my sleeves if that's what it takes.
Thanks in advance for your help.
|
|
|
|
|
I would strongly suggest you read my timers article.
Luc Pattyn [Forum Guidelines] [My Articles]
this weeks tips:
- make Visual display line numbers: Tools/Options/TextEditor/...
- show exceptions with ToString() to see all information
- before you ask a question here, search CodeProject, then Google
|
|
|
|
|
Very interesting article, and good demo application. That explains why I can't break the 65fps barrier using the timer control to trigger my rendering cycle. I've posted a response farther down this thread that explains why I was using a timer at all. I think your article is a good reason for getting rid of the timer and taking the approach listed in that other response.
|
|
|
|
|
Xpnctoc wrote: Since I want to draw as fast as possible, the timer interval is set to 1 ms.
Even if you could get an accurate timer event at 1ms intervals, why would you
ever need to redraw at that rate? Even a 20ms interval is way more than sufficient
for something a human is going to view, and would free up a LOT of CPU cycles for
doing other (more useful) things.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
The purpose of the timer was not to achieve a certain drawing rate. It was only to use the .NET event-driven model to create a rendering cycle. Having an interval of 1ms was only to eliminate any delay between rendering cycles.
Suppose I have a simple scene with 5000 triangles. That's a piece of cake for even the cheapest graphics card. Add a 20ms delay in between, and we get 49-50 fps. Fine. But suppose the scene to be rendered is sufficiently complex that even on an infinite loop the graphics card could only crank out 30fps. That means we're taking 33ms to render a single frame. If we have to wait 20ms in between each 33ms rendering because of the higher timer interval, that gives us 53ms per frame, or 18-19fps. And THAT starts looking choppy.
The only work-around I've been able to find is to put a loop in the Form::Shown event handler as follows:
<br />
void MyRenderingWindow::Shown(System::Object^ sender, System::EventArgs^ e)<br />
{<br />
while (Form::Created)<br />
{<br />
if (bDataAvailable)<br />
RenderScene();<br />
Application::DoEvents();<br />
}<br />
}<br />
Eliminating the timer completely gives me a framerate of 80 - 110fps in a range of 8k-12k triangles on my notebook. That's still under 1 million triangles per second, but it's more comforting than the 58-64fps I was getting before. I haven't tested this solution on my tower with the better graphics card yet.
The solution above seems kind of weird and kludgy. I'm open to other suggestions of how to set up a high speed rendering loop, with or without timers.
-- modified at 17:18 Saturday 22nd September, 2007
|
|
|
|
|
I've just read this thread and found it very interesting. I'm curious: Any solution in C++/CLI since 2007?
|
|
|
|
|
Over the past couple of years I have found a number of factors that enhance or inhibit performance. With regard to this immediate posting, I did remove the timer in favor of a petal-to-the-metal, untimed loop on the main application form Shown() event like this:
private void FMain::Shown(System::Object^ sender, System::EventArgs^ e)
{
while (Form::Created)
{
}
}
However, as I said, there are many other factors that I've learned about:
1. Running through Visual Studio is notably slower than native execution. No doubt this is due to the debugging/tracing layer involved.
2. If your video card has V-sync, that can mess you up. It explains why my piece of junk notebook was cranking out 122 FPS while my $250 NVidia graphics card on my tower was still topping out at 75 FPS. The problem is that without V-sync, you can get weird artifacts like image "tearing".
3. At the time I made the original post, all my graphics code was using straight-up graphics commands like glVertex3d(). Since then I have refactored my code to use vertex arrays. This does make for a significant gain -- especially in complex shapes like cylinders. After all, it's a waste to perform all those SIN and COS calculations every cycle.
While V-sync limits the max frame rate, #1 and #3 allow the frame rate to remain maxed out over a lot higher count of triangles before things start to drop off.
|
|
|
|
|
Dear Xpnctoc
Thank you for your answer. As a conclusion, you could enhance the performance. Still I am interested in one thing: Do you have the impression that native execution of managed C++ code is still slower than native execution of unmanaged code?
Regs
U. Kant
|
|
|
|
|
That depends on exactly what type of code.
As far as my original post goes, the answer is no, I don't believe it's any slower. But my game is using "mixed mode" programming, and all of my graphics calls are technically unmanaged. What was slowing me down was the use of a timer to regulate the rendering loop, which I never did in strictly unmanaged applications. In other words, I got myself confused.
There are, of course, managed graphics library wrappers (i.e., in C#). I haven't played with those much, but I would expect them to be a little slower just because they have to go through the extra step to convert their managed calls into unmanaged calls to the native OpenGL API anyway.
One more thing to be aware of, though it may be a little off topic. The answer to your question outside of graphics programming can be a definitive "yes"! For instance, invoking the Sort() method on a System::Collections::Generic::List class is WAY slower than a hand-coded, native mode Quick Sort.
This is why I'm writing my game in mixed mode. I use .NET to make life easier as far as pop-up messages, dialog boxes, etc (if you've ever used MFC you know what a pain that can be). But all of my core gaming logic and graphics calls are written in unmanaged classes to avoid as much "middle-man" junk as I can.
|
|
|
|
|
Dear Xpnctoc
Again thank you for sharing your experience. You've answered both of my issues: First think I was interested in was if embedding performance-critical code in native objects and seperating this layer strictly from the managed code actually works and performance does not go down for some reason.
Thus I will go forward with my plan and implement all of my code in C++/CLI except high-performance alorithms i n native C++. My strategy is very similar to yours: Use .NET for all the stuff around and native C++ for the critical stuff.
Cheers
UK
|
|
|
|
|
Hi,
Please consider the following interface in C++.Net
public __interface IAnimal<br />
{<br />
void Eat(String^ food);<br />
};<br />
when I try to implement this in a C# class...
class Dog : IAnimal<br />
{<br />
...<br />
}<br />
It gives me an error "error CS0509: 'Dog': cannot derive from sealed type 'IAnimal'"
What am I doing wrong here?
SDX2000
SDX2000
|
|
|
|
|
Don't you want a managed C++ interface class instead?
public interface class IAnimal<br />
{...<br />
<br />
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thanks for pointing this out. I have used C++ and C# but I am new to C++/CLI. This works as desired.
SDX2000
|
|
|
|
|
Hi All..
I have a confusion,,,,can I declare a vector of class instances as a data member in the class itself...and can I use that vector in that class...
like..
class printer{
string Printername;
unsigned int PrinterPort;
.................
...............
vector<printer*> m_vectPrinter;
please help me
Rashmi
|
|
|
|
|
Hi,
yes you can do such things, in C# you would do something like:
static ArrayList allPrinters1;
static List<printer> allPrinters2;
and there must be an equivalent in C++.
You may add initialization code:
static ArrayList allPrinters1=new ArrayList();
static List<printer> allPrinters2=new List<printer>();
You could add code to the constructor so it automatically adds the newly created
printer ("this") to the collection.
Luc Pattyn [Forum Guidelines] [My Articles]
this weeks tips:
- make Visual display line numbers: Tools/Options/TextEditor/...
- show exceptions with ToString() to see all information
- before you ask a question here, search CodeProject, then Google
|
|
|
|
|
Is there a way to copy the events associated with a control to another control?
Like this ( will give a compiler error )
this->button->click = this->otherbutton->click;
Thanks
PS this relates to my earlier post
Programmer
Glenn Earl Graham
Austin, TX
|
|
|
|
|
If button and otherbutton is set up this way:
this->button->Click += gcnew System::EventHandler(this, &Form1::button_Click);
this->otherbutton->Click += gcnew System::EventHandler(this, &Form1::otherbutton_Click);
then you can add "otherbutton" to also handle button's event thus:
this->button->Click += gcnew System::EventHandler(this, &Form1::otherbutton_Click);
"We make a living by what we get, we make a life by what we give." --Winston Churchill
|
|
|
|
|
I have a list of control names (in String form). Not the WinForm control object but the name of the control object. I need to call the click event associated with that control. I need to do this at run time dynamically.
Is there a way to call that event?
Not this is for a Window Form running in a C++ environment.
Hope you can point me in the right direction.
Thanks
Programmer
Glenn Earl Graham
Austin, TX
|
|
|
|
|
|
I have a Listview window with 10 columns. Data are display in the column going left to right with the newest data at the right most column. A horizontal scrollbar is automatically displayed at the bottom and the thumb of the scrollbar is at the left side. I want to put the thumb of the scrollbar to the right side so the when you go to that window you see the newest data first. I tried using GetScrollInfo() but I keep on getting "The window does not have scroll bars." from GetLastError(). I tried using SetScrollInfo() and passing in different values for nPos of the SCROLLINFO structure to see if it would move the thumb, but it doesn't seem to work. Does anyone know how you I get the thumb of the scrollbar to be at the right side?
|
|
|
|
|
|
Hi Mark, thanks for the help, ListView_Scroll() solved the problem I asked. Now I have another problem, when I press the left or right arrow on the scrollbar, I don't receive any WM_HSCROLL messages. I need to check when the thumb is at the far right and the right arrow is press I need to check for newer data and when the thumb is at the far left and the left arrow is press to retrieve older data. Any suggestion why I am not receiving any WM_HSCROLL messages?
|
|
|
|
|
Same situation - we don't know how the common controls are implemented internally
so we can't assume these window messages are available in the standard way.
Just like you should be using ListView messages to control the control ( ), you should
be looking for ListView notifications (LVN_xxxx) instead of standard window messages.
See LVN_BEGINSCROLL/LVN_ENDSCROLL
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
FYI...
I recommend keeping a link to this:
Control Library[^]
or the equivalent link in your local development MSDN library.
It's the documentation for all the Windows common controls, including messages,
notifications, and APIs.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi, I am using Visual Studio 2005 C++/CLI. I have been trying to populate a cell in a grid control but I haven't been able to find any examples that are not C#. I thought I needed to do something like...
DataGridViewCell myCell = gcnew DataGridViewCell(rowValue, colValue);
dataGridview1->CurrentCell = myCell;
dataGridView1->CurrentCell->Value = "Test";
The compiler complains that an abstact class cannot be instantiated. If anyone knows of a link to a CLI example that would be great. I just can't quit seem to figure out how to populate the cells of the DataGridView control (the microsoft .NET documentation hasn't helped).
Thanks
Buck
|
|
|
|