Subversion Repositories Games.Descent

Rev

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
}