Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 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 | } |