1 //========================================================================
2 // Vsync enabling test
3 // Copyright (c) Camilla Berglund <elmindreda@glfw.org>
4 //
5 // This software is provided 'as-is', without any express or implied
6 // warranty. In no event will the authors be held liable for any damages
7 // arising from the use of this software.
8 //
9 // Permission is granted to anyone to use this software for any purpose,
10 // including commercial applications, and to alter it and redistribute it
11 // freely, subject to the following restrictions:
12 //
13 // 1. The origin of this software must not be misrepresented; you must not
14 // claim that you wrote the original software. If you use this software
15 // in a product, an acknowledgment in the product documentation would
16 // be appreciated but is not required.
17 //
18 // 2. Altered source versions must be plainly marked as such, and must not
19 // be misrepresented as being the original software.
20 //
21 // 3. This notice may not be removed or altered from any source
22 // distribution.
23 //
24 //========================================================================
25 //
26 // This test renders a high contrast, horizontally moving bar, allowing for
27 // visual verification of whether the set swap interval is indeed obeyed
28 //
29 //========================================================================
30
31 #include <glad/glad.h>
32 #include <GLFW/glfw3.h>
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <math.h>
37
38 #include "getopt.h"
39
40 static int swap_tear;
41 static int swap_interval;
42 static double frame_rate;
43
usage(void)44 static void usage(void)
45 {
46 printf("Usage: tearing [-h] [-f]\n");
47 printf("Options:\n");
48 printf(" -f create full screen window\n");
49 printf(" -h show this help\n");
50 }
51
update_window_title(GLFWwindow * window)52 static void update_window_title(GLFWwindow* window)
53 {
54 char title[256];
55
56 sprintf(title, "Tearing detector (interval %i%s, %0.1f Hz)",
57 swap_interval,
58 (swap_tear && swap_interval < 0) ? " (swap tear)" : "",
59 frame_rate);
60
61 glfwSetWindowTitle(window, title);
62 }
63
set_swap_interval(GLFWwindow * window,int interval)64 static void set_swap_interval(GLFWwindow* window, int interval)
65 {
66 swap_interval = interval;
67 glfwSwapInterval(swap_interval);
68 update_window_title(window);
69 }
70
error_callback(int error,const char * description)71 static void error_callback(int error, const char* description)
72 {
73 fprintf(stderr, "Error: %s\n", description);
74 }
75
framebuffer_size_callback(GLFWwindow * window,int width,int height)76 static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
77 {
78 glViewport(0, 0, width, height);
79 }
80
key_callback(GLFWwindow * window,int key,int scancode,int action,int mods)81 static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
82 {
83 if (action != GLFW_PRESS)
84 return;
85
86 switch (key)
87 {
88 case GLFW_KEY_UP:
89 {
90 if (swap_interval + 1 > swap_interval)
91 set_swap_interval(window, swap_interval + 1);
92 break;
93 }
94
95 case GLFW_KEY_DOWN:
96 {
97 if (swap_tear)
98 {
99 if (swap_interval - 1 < swap_interval)
100 set_swap_interval(window, swap_interval - 1);
101 }
102 else
103 {
104 if (swap_interval - 1 >= 0)
105 set_swap_interval(window, swap_interval - 1);
106 }
107 break;
108 }
109
110 case GLFW_KEY_ESCAPE:
111 glfwSetWindowShouldClose(window, 1);
112 break;
113 }
114 }
115
main(int argc,char ** argv)116 int main(int argc, char** argv)
117 {
118 int ch, width, height;
119 float position;
120 unsigned long frame_count = 0;
121 double last_time, current_time;
122 int fullscreen = GLFW_FALSE;
123 GLFWmonitor* monitor = NULL;
124 GLFWwindow* window;
125
126 while ((ch = getopt(argc, argv, "fh")) != -1)
127 {
128 switch (ch)
129 {
130 case 'h':
131 usage();
132 exit(EXIT_SUCCESS);
133
134 case 'f':
135 fullscreen = GLFW_TRUE;
136 break;
137 }
138 }
139
140 glfwSetErrorCallback(error_callback);
141
142 if (!glfwInit())
143 exit(EXIT_FAILURE);
144
145 if (fullscreen)
146 {
147 const GLFWvidmode* mode;
148
149 monitor = glfwGetPrimaryMonitor();
150 mode = glfwGetVideoMode(monitor);
151
152 glfwWindowHint(GLFW_RED_BITS, mode->redBits);
153 glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
154 glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
155 glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
156
157 width = mode->width;
158 height = mode->height;
159 }
160 else
161 {
162 width = 640;
163 height = 480;
164 }
165
166 window = glfwCreateWindow(width, height, "", monitor, NULL);
167 if (!window)
168 {
169 glfwTerminate();
170 exit(EXIT_FAILURE);
171 }
172
173 glfwMakeContextCurrent(window);
174 gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
175 set_swap_interval(window, 0);
176
177 last_time = glfwGetTime();
178 frame_rate = 0.0;
179 swap_tear = (glfwExtensionSupported("WGL_EXT_swap_control_tear") ||
180 glfwExtensionSupported("GLX_EXT_swap_control_tear"));
181
182 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
183 glfwSetKeyCallback(window, key_callback);
184
185 glMatrixMode(GL_PROJECTION);
186 glOrtho(-1.f, 1.f, -1.f, 1.f, 1.f, -1.f);
187 glMatrixMode(GL_MODELVIEW);
188
189 while (!glfwWindowShouldClose(window))
190 {
191 glClear(GL_COLOR_BUFFER_BIT);
192
193 position = cosf((float) glfwGetTime() * 4.f) * 0.75f;
194 glRectf(position - 0.25f, -1.f, position + 0.25f, 1.f);
195
196 glfwSwapBuffers(window);
197 glfwPollEvents();
198
199 frame_count++;
200
201 current_time = glfwGetTime();
202 if (current_time - last_time > 1.0)
203 {
204 frame_rate = frame_count / (current_time - last_time);
205 frame_count = 0;
206 last_time = current_time;
207 update_window_title(window);
208 }
209 }
210
211 glfwTerminate();
212 exit(EXIT_SUCCESS);
213 }
214
215