Author Topic: Opengl Performance / Sleep time  (Read 11148 times)

0 Members and 1 Guest are viewing this topic.

Charles Pegge

  • Guest
Opengl Performance / Sleep time
« on: April 18, 2014, 07:15:15 PM »

Topic branch from:
http://www.thinbasic.com/community/showthread.php?12414-Benchmarking-against-functional-languages&p=91053#post91053

Thanks Mike,

That indicates to me that the only reliable time measure is from the real-time clock.

But I have a vested interested in dynamic measurements. I want my opengl animations to remain in sync with a quantum of the frame rate, while filling in with a variable sleep period.

If one of the frames is missed, the next scene is time-step calculated to compensate for this, and the sleep period is reduced.

The sleep period is then gradually increased until the next missed frame.

The intended result is smooth animation while running with the minimum CPU load.

It assume that CPU time is the limiting factor, not GPU rendering time

This is what I have so far:

Code: [Select]
'FRAME SYNC SLEEP
===============
static quad   t1,t2
static float fperiod, stime=16.0
static sys fstep, sl
t1=t2
TimeMark t2
fperiod=TimeDiff t2,t1
fstep=1
stime+=.01
if fperiod
  if fperiod>.02 'quantum 60Hz 0.0166
    if stime>1.0
      stime-=1.0
      fstep=round(fperiod*60.0)
    end if
  end if
end if
sl=stime
SetWindowText hWnd, " " str(stime,3)
ang1+=angi1*fstep
if ang1>360 then ang1-=360
'...build scene...
if sl then sleep sl

Peter

  • Guest
Re: Opengl Performance / Sleep time
« Reply #1 on: April 19, 2014, 05:12:49 AM »
Hi Charles,

here's my time measuring, and how I did it.

Code: [Select]
include "sw.inc"
Window 800,600,1

quad t1, t2
quad freq
double elapsed

p = LoadBmp "bmp/pictree.bmp",1

QueryPerformanceFrequency freq
QueryPerformanceCounter t1

for x=0 to 799
for y=0 to 599
    color = GetBmpPixel p,x,y
    r = GetR(color)
    g = GetG(color)
    b = GetB(color)
    SetPixel x,y, RGB(r,g,b)
next
next

QueryPerformanceCounter t2
elapsed = (t2-t1) * 1000.0 / freq

SetCaption "TIME: " + elapsed + " msec"
WaitKey
CloseWindow

.

Peter

  • Guest
Re: Opengl Performance / Sleep time
« Reply #2 on: April 19, 2014, 05:21:56 AM »
Replace this for a fair and beautiful blueish : 
Code: [Select]
SetPixel x,y, RGB(r*.4,g*.6,b*.8)

Mike Lobanovsky

  • Guest
Re: Opengl Performance / Sleep time
« Reply #3 on: April 19, 2014, 08:06:45 PM »
Hello Charles,

Sorry for being late to answer but my matters took me a little longer than I'd planned. And I also needed time to prepare for the conversation refreshening what was forgotten in the past three years.

So let's start with a Happy Easter to you and the OxygenBasic community! :)

Now to the subject matter. Everything that I have to say is based on my own experience and a hell of a lot of trial and error. Be assured that I've turned over a pile of relevant literature and web data learning my lessons the hard way.


Part I: Sleep() Considerations

While the idea of using Sleep() to control your framerate may seem attractive, it has several serious drawbacks:

1. Besides timing per se you have to deal with similar inherent inaccuracy of Sleep(), which effectively doubles the number of disturbing factors in your rendering loop.

2. For heavily populated and textured scenes, Sleep()'s resolution may need to go down arithmetically to a sub-tick level within the rigid 60 (or 30) FPS constrains imposed by VSYNC. This isn't however possible. The default resolution of Sleep() is 16 ticks for an NT-based kernel and it can only be changed using a call to timeBeginPeriod(n) which resides in Winmm.dll. (Be sure to use a matching call to timeEndPeriod(n) while experimenting or your system clock potentially being used by other concurrent processes may be compromised till the very end of the current session!)

The finest setting of n in this call is 1 tick and you can't go any lower. 1 tick is however very nice for other applications not related to OpenGL, isn't it? :)

3. An excellent Windows OpenGL implementation by nVidia (you have an nVidia video card, haven't you?) is a multi-threaded application that has its own timing facilities and optimum strategies targeting the fastest (and smoothest) rendering on a given HW platform.

For example, if you open up your nVidia Control Center, you may find the following setting there (that's my Vista setup with the latest nVidia drivers installed):


As you see, OpenGL can spawn (of course depending on your CPU) up to 4 additional threads to pre-calculate and pre-render in advance up to 4 frames of your video flow. Clear enough, it can do it only if the remaining time slice so permits. Meddling with Sleep() in the program code may severely compromize OpenGL's abilities to self-control.

There may appear other unexpected bottlenecks in OpenGL depending on whether it has sufficient time to perform all the tasks scheduled for the current time- and render-frame for the given system settings and a particular rendering strategy (immediate mode, display lists, VBO's, shaders) and its dependencies.

So Sleep() is too rough an instrument to slice OpenGL with except some very rare cases where its current implementation is not flexible enough to give us what we need. Such cases are usually labeled with "upgrade your hardware" verdict.


Conclusion

Subsequent Parts will follow depending on how our discussion is going to develop. All my illustrations and explanations (but not the source code, sorry) will be based on i) the most stringent conditions our XANEngine has ever faced, and ii) on the real-world data from the Resident Evil 5: Lost in Nightmares (Playstation 2) game package.

You can download a freeware version of Resident Evil 5 Benchmark Edition for desktop PC's to see how poor your computer hardware really is by Capcom Ltd.'s standards:



I remember I was so dissatisfied with their verdict that I accepted my French friend's invitation to join him in the XANEngine project without hesitation to show the Japs how terribly wrong they were with their miserable attempts to lure us into buying their overpriced Playstations. :)
« Last Edit: April 19, 2014, 09:44:56 PM by Mike Lobanovsky »

Charles Pegge

  • Guest
Re: Opengl Performance / Sleep time
« Reply #4 on: April 20, 2014, 03:27:26 AM »
Thanks Mike,

I confirm that Opengl, when left to its own devices, takes care of frame timing and economical use of CPU time, without the aid of sleep.

This scene (examples/opengl/CraftControl.o2bas) is a useful test model for timing. Currently it runs at 2..4 % of CPU time (Task Manager), and takes 0.02.. 0.04 milliseconds to render (Client side/QueryPerformanceCounter).

Even when the Windows Timer message is set to 10 msec, Frames are missed. About 2 are dropped per second. It is useful to be able to detect when this happens and compensate movement accordingly.


.
« Last Edit: April 20, 2014, 04:00:58 AM by Charles Pegge »

Mike Lobanovsky

  • Guest
Re: Opengl Performance / Sleep time
« Reply #5 on: April 20, 2014, 04:02:35 AM »
Hehe, a nice toy you have here! The file is however called ControlCraft.o2bas... :)

1. It loads my 4-core CPU up to 50% which would equal ~100% on a Core2 Duo.

2. I see absolutely no frame drop-outs whatsoever. Movement is perfectly smooth.

3. Knobs won't turn around the dial completely but within ~90 degrees from approx. 1 o'clock to some 5 or 6 o'clock only.

Fraps gives perfectly stable 60FPS. Any comments?

P.S. Is the light source supposed to be moving? Don't see it on the UFO's surface but the shadow beneath the hull goes round in circles...

[UPD] That's when my nVidia Control Center settings are set to "Settings controlled by application" (I'm currently under XP and my Control Center is in Russian; I have to translate) - that's the top option selected. When the bottom option is selected and its slider is set to "Optimize for speed" (that effectively overrides your programmatic VSYNC), the rate can reach 150FPS full-screen but it also fluctuates severely when I move my mouse across the screen. Also, when the mouse moves over the console, the UFO starts to jerk on its way. But the CPU load is close to nil! Still any comments? What do you see on your monitor under all these conditions? Should I switch to Vista to go on testing?
« Last Edit: April 20, 2014, 04:22:05 AM by Mike Lobanovsky »

Charles Pegge

  • Guest
Re: Opengl Performance / Sleep time
« Reply #6 on: April 20, 2014, 05:57:53 AM »
Mike,

It's a pseudo shadow :)

The controls are only there for earthlings, of course.

I'm not sure whether you have the latest openglsceneframe. so I attach it here (for the inc folder). In this configuration, there is no glfinish, which whacked it up to 34% CPU usage on my quad core . In any case, it should be sufficient to comment out glfinish

PS: the knobs only respond to vertical drag, not yet rotary or horizontal. They are intended for something .. maybe the stereo.


.
« Last Edit: April 20, 2014, 06:28:14 AM by Charles Pegge »

Mike Lobanovsky

  • Guest
Re: Opengl Performance / Sleep time
« Reply #7 on: April 20, 2014, 05:03:56 PM »
Sorry Charles,

I just missed the most recent O2 update. Now I'm seeing better CPU performance but it's still absolutely unnatural.

I need some more time to examine your entire rendering loop. I think its implementation is not optimal as a whole. Yup, dropouts are more noticeable under Vista than under XP or 7. I'll come back to the topic as soon as I'm ready with my proposals, OK?

Charles Pegge

  • Guest
Re: Opengl Performance / Sleep time
« Reply #8 on: April 20, 2014, 08:20:41 PM »
Thanks for all your attention, Mike.

I think the frame loop is now a clean run for rendering. The windows timer can be set somewhere between 10.. 12 milliseconds - significantly less than 16, anyway. Otherwise missed frames escalate rapidly. I see no perceptible jitter on the saucer movement.

There are several frame modes to choose from. These are selected to eliminate unnecessary frame rendering. Here, we are only concerned with ActiveFrame

The key macros for Active Frame mode:

Code: [Select]
  macro TimeFrame
  ===============
  static sys   countn
  static float FramePeriod,stepn
  scope
  static quad   t1,t2
  stepn=1
  t1=t2
  TimeMark t2
  if t1
    FramePeriod=TimeDiff t2,t1
    if FramePeriod>.02              'quantum 60Hz 0.0166
      stepn=round(FramePeriod*60.0) 'moment scale
      countn+=stepn-1               'count missed frames
    end if
  end if
  end scope
  end macro


  macro NewFrame()
  ===================
  glClear GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT
  glEnable GL_DEPTH_TEST
  glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
  glEnable GL_BLEND
  glPolygonMode GL_FRONT_AND_BACK, GL_FILL
  glEnable GL_NORMALIZE
  glLoadIdentity
  end macro
  '
  macro ActiveFrame()
  ===================
  TimeFrame
  SnapShots(hwnd) 'Ctrl-P take snapshot
  NewFrame
  end macro

TimeFrame only provides timing data to the app.

Frame building is further elaborated by single-shot list compiling, and object-picking passes


Aurel

  • Guest
Re: Opengl Performance / Sleep time
« Reply #9 on: April 20, 2014, 09:40:16 PM »
Where is the source code of this example  ???

Charles Pegge

  • Guest
Re: Opengl Performance / Sleep time
« Reply #10 on: April 21, 2014, 01:37:22 AM »
Hi Aurel,

It is part of inc/OpenglSceneFrame.inc
and we are testing examples/opengl/ControlCraft.o2bas

Mike Lobanovsky

  • Guest
Re: Opengl Performance / Sleep time
« Reply #11 on: April 21, 2014, 01:50:58 AM »
Hello Charles,

On skimming through the sources, I think I should note the following:
-- while the solution seems to work more or less stable with a few hundred polies in view, still it depends on SetTimer() by implication;
-- the rendering loop is located in WndProc() while canonically it should be part of MainWindow()'s while/wend loop outside its if/else/endif conditional, that is occupy the remaining portion of the loop e.g. similar to Glut's Render() (=OnIdle()) callback. All Windows messages in the queue must have absolute priority over OpenGL until the entire queue is executed while OpenGL stands by, the timing procedure being supposed to further compensate for the lag that message execution might've introduced;
-- a lot of unnecessary OpenGL state changes are performed in each frame.

1. SetTimer() is OK for simple demos, examples, and proof of concept. But it's alien to OpenGL and may be the cause of race conditions. OpenGL is designed to operate at maximum speeds possible on a given HW platform and using non-native means to control its throughput may be detrimental for general-case solutions.

WM_TIMER has one of the lowest priorities among the entire range of messages in the message pipe. IIRC there's only one message that has a yet lower priority and that's WM_PAINT which may drop out of (be ignored by) the message pipe completely. The same goes about WM_TIMER; if the whole bunch of other messages and pending tasks take longer to execute than WM_TIMER's period, then the current WM_TIMER will be ignored (dropped out) till the next one comes and has a chance to execute. Similarly, if WM_TIMER's associated procedure is still executing while another WM_TIMER comes, that later message will be ignored and gone unnoticed.

2. I have a strong suspicion the entire FPS limiting is built around that SetTimer() setup. So far I haven't been able to locate a call to wglSwapIntervalEXT() that's OpenGL's only native means to synchronize its renders with the primary monitor's vertical retrace signal. Perhaps I'm simply missing it; there are a lot of includes I'm not familiar with yet.

3. There are many OpenGL states that, once set, are preserved till the very end of the program if only some specific entity in the scene, e.g. an OpenGL custom material, doesn't require a specific change of this or that parameter. If that happens, it is then the entity's task to switch the state back to what is supposed to be the parameter's default throughout the rest of the program. Otherwise, there's absolutely no need to re-set these states in every frame rendered.

Reducing the number of OpenGL state changes per frame is the programmer's most important strategic task. An extra glXXXXX() function call may seem irrelevant at the terrific speeds of a JIT compiler but it may intrinsically spawn to life thousands of code lines buried inside the OpenGL driver libraries. We're seeing only the top of the iceberg that may send our Titanic to the bottom in no time.

I can re-write this particular example to a minimum of how it should look from my perspective keeping its functionality intact, if you want me to. I will also comment my actions where needed. In case you're satisfied with the results, it may be expanded to interface with the solutions in other existing O2 includes. I'll refactor parts of  ControlCraft.o2bas, OpenglSceneFrame.inc, ControlPanels.inc, and WinUtil.inc.

If that's OK with you, please tell me:

1. Is a call to wglSwapIntervalEXT() still buried somewhere in nested includes?

1. Do you have an nVidia Control Center installed?

2. Do you have Fraps installed (window captions and console print are far too slow to monitor the FPS rate unobtrusively)?

Charles Pegge

  • Guest
Re: Opengl Performance / Sleep time
« Reply #12 on: April 21, 2014, 06:23:25 AM »
Mike,

My code is very changeable at present, and I am about to hook in real-time audio synth, but your ideas are very welcome, and I can try them out quite easily.

I tried putting the rendering call into the message loop, but without success. The frames are empty apart from the background color. Calling from wndproc is efficient - WM_TIMER is of course hopelessly inaccurate but serves as a 'tickler' to maintain a steady stream of messages.

Is a call to wglSwapIntervalEXT() still buried somewhere in nested includes?
I am testing it (after wglMakeCurrent)  but no difference in dropped frames.
Yes I believe it has made a difference. I only see dropped frames when the window is moved or resized.

1. Do you have an nVidia Control Center installed?
Yes, I am using the default settings

2. Do you have Fraps installed (window captions and console print are far too slow to monitor the FPS rate unobtrusively)?
Yes, I've installed it.
- then some disagreeable adware accompanied it and disrupted my browser, so I had to remove it.
« Last Edit: April 21, 2014, 08:40:07 AM by Charles Pegge »

Charles Pegge

  • Guest
Re: Opengl Performance / Sleep time
« Reply #13 on: April 21, 2014, 01:24:43 PM »
Location of wglSwapIntervalEXT in inc/openglSceneFrame.inc

  case WM_CREATE
  '
  'SETUP DEVICE CONTEXT AND RENDER CONTEXT
  '
  if minCreate then exit function
  hDC=GetDC hwnd
  SelectPixelformat()
  hRC = wglCreateContext hDC
  wglMakeCurrent hDC, hRC
  sys p=wglgetprocaddress "wglSwapIntervalEXT" : call p 1
  #ifdef fontA
  BuildFont hWnd, hDC, hRC,fontA,1024
  #endif
  #ifdef fontB
  BuildFont hWnd, hDC, hRC,fontB,1280
  #endif
  ! Initialize(sys hWnd) : Initialize hWnd
  SetWindowText hwnd,title

  act=2


No dropped frames (60fps), except at startup, or adjusting window. Occasionally when running at full-screen
CPU load: 3..5%

Mike Lobanovsky

  • Guest
Re: Opengl Performance / Sleep time
« Reply #14 on: April 21, 2014, 01:32:57 PM »
Very nice results, Charles, thanks a lot for the info. Yet I'm all set to try and implement my own solution tonight and I'll come back with it some time tomorrow.

[UPD on April 23] I'm sorry but yesterday I had two of my old friends drop in at my place quite unexpectedly so my creative potential is still close to nil. I will however come back to this topic as soon as I'm able to do away with my residual hangover. :)
« Last Edit: April 22, 2014, 09:21:47 PM by Mike Lobanovsky »