Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7.  
  8. /* OpenGL Synchronization code:
  9.  * either use fence sync objects or glFinish() to prevent the GPU from
  10.  * lagging behind too much.
  11.  */
  12.  
  13. #include <stdlib.h>
  14. #include <SDL.h>
  15.  
  16. #include "args.h"
  17. #include "config.h"
  18. #include "console.h"
  19. #include "game.h"
  20. #include "maths.h"
  21. #include "multi.h"
  22. #include "ogl_sync.h"
  23. #include "timer.h"
  24.  
  25. namespace dcx {
  26.  
  27. ogl_sync::ogl_sync()
  28. {
  29.         method=SYNC_GL_NONE;
  30.         wait_timeout = 0;
  31. }
  32.  
  33. ogl_sync::~ogl_sync()
  34. {
  35.         if (fence)
  36.                 con_puts(CON_URGENT, "DXX-Rebirth: OpenGL: fence sync object was never destroyed!");
  37. }
  38.  
  39. void ogl_sync::sync_deleter::operator()(GLsync fence_func) const
  40. {
  41.         glDeleteSyncFunc(fence_func);
  42. }
  43.  
  44. void ogl_sync::before_swap()
  45. {
  46.         if (const auto local_fence = std::move(fence))
  47.         {
  48.                 /// use a fence sync object to prevent the GPU from queuing up more than one frame
  49.                 const auto waitsync = glClientWaitSyncFunc;
  50.                 if (method == SYNC_GL_FENCE_SLEEP) {
  51.                         const auto local_wait_timeout = wait_timeout;
  52.                         const auto multiplayer = Game_mode & GM_MULTI;
  53.                         while (waitsync(local_fence.get(), GL_SYNC_FLUSH_COMMANDS_BIT, 0ULL) == GL_TIMEOUT_EXPIRED) {
  54.                                 if (multiplayer) {
  55.                                         multi_do_frame(); // during long wait, keep packets flowing
  56.                                 }
  57.                                 timer_delay_ms(local_wait_timeout);
  58.  
  59.                         }
  60.                 } else {
  61.                         waitsync(local_fence.get(), GL_SYNC_FLUSH_COMMANDS_BIT, 34000000ULL);
  62.                 }
  63.         } else if (method == SYNC_GL_FINISH_BEFORE_SWAP) {
  64.                 glFinish();
  65.         }
  66. }
  67. void ogl_sync::after_swap()
  68. {
  69.         if (method == SYNC_GL_FENCE || method == SYNC_GL_FENCE_SLEEP ) {
  70.                 fence.reset(glFenceSyncFunc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
  71.         } else if (method == SYNC_GL_FINISH_AFTER_SWAP) {
  72.                 glFinish();
  73.         }
  74. }
  75.  
  76. void ogl_sync::init(SyncGLMethod sync_method, int wait)
  77. {
  78.         method = sync_method;
  79.         fence = NULL;
  80.         fix a = i2f(wait);
  81.         fix b = i2f(1000);
  82.         wait_timeout = f2i(fixdiv(a, b) * 1000);
  83.  
  84.         bool need_ARB_sync;
  85.  
  86.         switch (method) {
  87.                 case SYNC_GL_FENCE:
  88.                 case SYNC_GL_FENCE_SLEEP:
  89.                 case SYNC_GL_AUTO:
  90.                         need_ARB_sync = true;
  91.                         break;
  92.                 default:
  93.                         need_ARB_sync = false;
  94.         }
  95.  
  96.         if (method == SYNC_GL_AUTO) {
  97.                 if (!CGameCfg.VSync) {
  98.                         con_puts(CON_NORMAL, "DXX-Rebirth: OpenGL: disabling automatic GL sync since VSync is turned off");
  99.                         method = SYNC_GL_NONE;
  100.                         need_ARB_sync = false;
  101.                 } else if (!ogl_have_ARB_sync) {
  102.                         con_puts(CON_NORMAL, "DXX-Rebirth: OpenGL: GL_ARB_sync not available, disabling sync");
  103.                         method = SYNC_GL_NONE;
  104.                         need_ARB_sync = false;
  105.                 } else {
  106.                         method = SYNC_GL_FENCE_SLEEP;
  107.                 }
  108.         }
  109.  
  110.         if (need_ARB_sync && !ogl_have_ARB_sync) {
  111.                 con_puts(CON_URGENT, "DXX-Rebirth: OpenGL: GL_ARB_sync not available, using fallback");
  112.                 method = SYNC_GL_FINISH_BEFORE_SWAP;
  113.         }
  114.         switch(method) {
  115.                 case SYNC_GL_FENCE:
  116.                         con_puts(CON_VERBOSE, "DXX-Rebirth: OpenGL: using GL_ARB_sync for synchronization (direct)");
  117.                         break;
  118.                 case SYNC_GL_FENCE_SLEEP:
  119.                         con_printf(CON_VERBOSE, "DXX-Rebirth: OpenGL: using GL_ARB_sync for synchronization with interval %dms", wait);
  120.                         break;
  121.                 case SYNC_GL_FINISH_AFTER_SWAP:
  122.                         con_puts(CON_VERBOSE, "DXX-Rebirth: OpenGL: using glFinish synchronization (method 1: after swap)");
  123.                         break;
  124.                 case SYNC_GL_FINISH_BEFORE_SWAP:
  125.                         con_puts(CON_VERBOSE, "DXX-Rebirth: OpenGL: using glFinish synchronization (method 2: before swap)");
  126.                         break; 
  127.                 default:       
  128.                         con_puts(CON_VERBOSE, "DXX-Rebirth: OpenGL: using no explicit GPU synchronization");
  129.                         break;
  130.         }
  131. }
  132.  
  133. void ogl_sync::deinit()
  134. {
  135.         fence.reset();
  136. }
  137.  
  138. }
  139.