c++ - Efficient sync function for an OpenGL window -


what efficient , accurate way of syncing frames per second in opengl window using c++. have tried putting sleep(17); in main game loop , gets down 59 frames per second not accurate , efficient. here opengl window code without sleep(17); in main loop:

#include <windows.h> #include <gl\gl.h>  hdc hdc = null; hglrc hrc = null; hwnd hwnd = null; hinstance hinstance;  bool keys[256]; bool active = true;  lresult callback wndproc(hwnd, uint, wparam, lparam);  glvoid resizeglscene(glsizei width, glsizei height) {     if (height == 0)     {         height = 1;     }      glviewport(0, 0, width, height);      glmatrixmode(gl_projection);     glloadidentity();     glortho(0, 800, 0, 600, 1, -1);     glmatrixmode(gl_modelview); }  int initgl(glvoid) {     glshademodel(gl_smooth);     glclearcolor(0.0f, 0.0f, 0.0f, 0.5f);     glcleardepth(1.0f);     glenable(gl_depth_test);     gldepthfunc(gl_lequal);     glhint(gl_perspective_correction_hint, gl_nicest);     return 1; }  int drawglscene(glvoid) {     glclear(gl_color_buffer_bit | gl_depth_buffer_bit);     glloadidentity();      return 1; }  glvoid killglwindow(glvoid) {     if (hrc)     {         if (!wglmakecurrent(null,null))         {             messagebox(null, "release of dc , rc failed." ,"shutdown error" ,mb_ok | mb_iconinformation);         }          if (!wgldeletecontext(hrc))         {             messagebox(null, "release rendering context failed.", "shutdown error", mb_ok | mb_iconinformation);         }         hrc = null;     }      if (hdc && !releasedc(hwnd, hdc))     {         messagebox(null, "release device context failed.", "shutdown error", mb_ok | mb_iconinformation);         hdc = null;     }      if (hwnd && !destroywindow(hwnd))     {         messagebox(null, "could not release hwnd.", "shutdown error", mb_ok | mb_iconinformation);         hwnd = null;     }      if (!unregisterclass("project2dclass",hinstance))     {         messagebox(null, "could not unregister class.", "shutdown error", mb_ok | mb_iconinformation);         hinstance = null;     } }  bool createglwindow(char* title, int width, int height, int bits) {     gluint pixelformat;     wndclass wc;     dword dwexstyle;     dword dwstyle;     rect windowrect;     windowrect.left = (long)0;     windowrect.right = (long)width;     windowrect.top = (long)0;     windowrect.bottom = (long)height;      hinstance = getmodulehandle(null);     wc.style = cs_hredraw | cs_vredraw | cs_owndc;     wc.lpfnwndproc = (wndproc) wndproc;     wc.cbclsextra = 0;     wc.cbwndextra = 0;     wc.hinstance = hinstance;     wc.hicon = loadicon(null, idi_winlogo);     wc.hcursor = loadcursor(null, idc_arrow);     wc.hbrbackground = null;     wc.lpszmenuname = null;     wc.lpszclassname = "project2dclass";      if (!registerclass(&wc))     {         messagebox(null, "failed register window class.", "error", mb_ok|mb_iconexclamation);         return 0;     }      dwexstyle = ws_ex_appwindow | ws_ex_windowedge;     dwstyle = ws_overlappedwindow;      adjustwindowrectex(&windowrect, dwstyle, false, dwexstyle);      if (!(hwnd = createwindowex(             dwexstyle,             "project2dclass",             title,             dwstyle | ws_clipsiblings | ws_clipchildren,             0,             0,             windowrect.right-windowrect.left,             windowrect.bottom-windowrect.top,             null,             null,             hinstance,             null))     )     {         killglwindow();         messagebox(null, "window creation error.", "error", mb_ok | mb_iconexclamation);         return 0;     }      static  pixelformatdescriptor pfd =     {         sizeof(pixelformatdescriptor),         1,         pfd_draw_to_window | pfd_support_opengl | pfd_doublebuffer,         pfd_type_rgba,         bits,         0,          0,         0,          0,          0,         0,         0,         0,         0,         0,          0,         0,         0,         32,         0,         0,         pfd_main_plane,         0,         0,         0,          0     };      if (!(hdc = getdc(hwnd)))     {         killglwindow();         messagebox(null, "can't create gl device context.", "error", mb_ok|mb_iconexclamation);         return 0;     }      if (!(pixelformat=choosepixelformat(hdc, &pfd)))     {         killglwindow();         messagebox(null, "can't find suitable pixelformat.", "error", mb_ok|mb_iconexclamation);         return 0;     }      if(!setpixelformat(hdc, pixelformat, &pfd))     {         killglwindow();         messagebox(null,"can't set pixelformat.","error",mb_ok|mb_iconexclamation);         return 0;     }      if (!(hrc = wglcreatecontext(hdc)))     {         killglwindow();         messagebox(null, "can't create gl rendering context.", "error", mb_ok|mb_iconexclamation);         return 0;     }      if(!wglmakecurrent(hdc, hrc))     {         killglwindow();         messagebox(null,"can't activate gl rendering context.", "error", mb_ok|mb_iconexclamation);         return 0;     }      showwindow(hwnd, sw_show);     setforegroundwindow(hwnd);     setfocus(hwnd);     resizeglscene(width, height);      if (!initgl())     {         killglwindow();         messagebox(null, "initialization failed.", "error", mb_ok|mb_iconexclamation);         return 0;     }      return 1; }  lresult callback wndproc(hwnd hwnd, uint umsg, wparam wparam, lparam lparam) {     switch (umsg)     {         case wm_activate:         {             if (!hiword(wparam))             {                 active = true;             }             else             {                 active = false;             }              return 0;         }          case wm_syscommand:         {             switch (wparam)             {                 case sc_screensave:                 case sc_monitorpower:                 return 0;             }             break;         }          case wm_close:         {             postquitmessage(0);             return 0;         }          case wm_keydown:         {             keys[wparam] = true;             return 0;         }          case wm_keyup:         {             keys[wparam] = false;             return 0;         }          case wm_size:         {             resizeglscene(loword(lparam), hiword(lparam));             return 0;         }     }      return defwindowproc(hwnd, umsg, wparam, lparam); }  int winapi winmain(hinstance hinstance, hinstance hprevinstance, lpstr lpcmdline, int ncmdshow) {     msg     msg;     bool    running = true;      if (!createglwindow("project 2d", 800, 600, 32))     {         return 0;     }      while(running)     {         if (peekmessage(&msg, null, 0, 0, pm_remove))         {             if (msg.message == wm_quit)             {                 running = false;             }             else             {                 translatemessage(&msg);                 dispatchmessage(&msg);             }         }         else         {              if (active)             {                 if (keys[vk_escape])                 {                     running = false;                 }                 else                 {                     drawglscene();                     swapbuffers(hdc);                 }             }         }     }     killglwindow();     return (msg.wparam); } 

and also, how can window launch in middle of screen.

edit:

here java equivalent off lwjgl framework:

/*  * copyright (c) 2002-2012 lwjgl project  * rights reserved.  *  * redistribution , use in source , binary forms, or without  * modification, permitted provided following conditions  * met:  *  * * redistributions of source code must retain above copyright  *   notice, list of conditions , following disclaimer.  *  * * redistributions in binary form must reproduce above copyright  *   notice, list of conditions , following disclaimer in  *   documentation and/or other materials provided distribution.  *  * * neither name of 'lwjgl' nor names of  *   contributors may used endorse or promote products derived  *   software without specific prior written permission.  *  * software provided copyright holders , contributors  * "as is" , express or implied warranties, including, not limited  * to, implied warranties of merchantability , fitness particular  * purpose disclaimed. in no event shall copyright owner or  * contributors liable direct, indirect, incidental, special,  * exemplary, or consequential damages (including, not limited to,  * procurement of substitute goods or services; loss of use, data, or  * profits; or business interruption) caused , on theory of  * liability, whether in contract, strict liability, or tort (including  * negligence or otherwise) arising in way out of use of  * software, if advised of possibility of such damage.  */ package org.lwjgl.opengl;  import org.lwjgl.sys;  /** * highly accurate sync method continually adapts system  * runs on provide reliable results. * * @author riven * @author kappaone */ class sync {      /** number of nano seconds in second */     private static final long nanos_in_second = 1000l * 1000l * 1000l;      /** time sleep/yield until next frame */     private static long nextframe = 0;      /** whether initialisation code has run */     private static boolean initialised = false;      /** calculating averages previous sleep/yield times stored */     private static runningavg sleepdurations = new runningavg(10);     private static runningavg yielddurations = new runningavg(10);       /**      * accurate sync method attempt run @ constant frame rate.      * should called once every frame.      *       * @param fps - desired frame rate, in frames per second      */     public static void sync(int fps) {         if (fps <= 0) return;         if (!initialised) initialise();          try {             // sleep until average sleep time greater time remaining till nextframe             (long t0 = gettime(), t1; (nextframe - t0) > sleepdurations.avg(); t0 = t1) {                 thread.sleep(1);                 sleepdurations.add((t1 = gettime()) - t0); // update average sleep time             }              // dampen sleep average if high avoid yielding             sleepdurations.dampenforlowresticker();              // yield until average yield time greater time remaining till nextframe             (long t0 = gettime(), t1; (nextframe - t0) > yielddurations.avg(); t0 = t1) {                 thread.yield();                 yielddurations.add((t1 = gettime()) - t0); // update average yield time             }         } catch (interruptedexception e) {          }          // schedule next frame, drop frame(s) if late next frame         nextframe = math.max(nextframe + nanos_in_second / fps, gettime());     }      /**      * method initialise sync method setting initial      * values sleepdurations/yielddurations , nextframe.      *       * if running on windows start sleep timer fix.      */     private static void initialise() {         initialised = true;          sleepdurations.init(1000 * 1000);         yielddurations.init((int) (-(gettime() - gettime()) * 1.333));          nextframe = gettime();          string osname = system.getproperty("os.name");          if (osname.startswith("win")) {             // on windows sleep functions can highly inaccurate              // on 10ms making in unusable. can forced              // bit more accurate running separate sleeping daemon             // thread.             thread timeraccuracythread = new thread(new runnable() {                 public void run() {                     try {                         thread.sleep(long.max_value);                     } catch (exception e) {}                 }             });              timeraccuracythread.setname("lwjgl timer");             timeraccuracythread.setdaemon(true);             timeraccuracythread.start();         }     }      /**      * system time in nano seconds      *       * @return return current time in nano's      */     private static long gettime() {         return (sys.gettime() * nanos_in_second) / sys.gettimerresolution();     }      private static class runningavg {         private final long[] slots;         private int offset;          private static final long dampen_threshold = 10 * 1000l * 1000l; // 10ms         private static final float dampen_factor = 0.9f; // don't change: 0.9f right!          public runningavg(int slotcount) {             this.slots = new long[slotcount];             this.offset = 0;         }          public void init(long value) {             while (this.offset < this.slots.length) {                 this.slots[this.offset++] = value;             }         }          public void add(long value) {             this.slots[this.offset++ % this.slots.length] = value;             this.offset %= this.slots.length;         }          public long avg() {             long sum = 0;             (int = 0; < this.slots.length; i++) {                 sum += this.slots[i];             }             return sum / this.slots.length;         }          public void dampenforlowresticker() {             if (this.avg() > dampen_threshold) {                 (int = 0; < this.slots.length; i++) {                     this.slots[i] *= dampen_factor;                 }             }         }     } } 

swapbuffers vertical retrace synchronization (v-sync) enabled. unless disabled in graphics driver should enabled default. can use swap interval extension fine tune ratio between swapbuffers timing , display vertical retrace.

also, since windows it's cpu time consumption calculation wrongly, add sleep(0) after swapbuffers, fixes issue of high indicated cpu load.


Comments

Popular posts from this blog

java.util.scanner - How to read and add only numbers to array from a text file -

rewrite - Trouble with Wordpress multiple custom querystrings -