SUMMARY
It seems that vsync with OpenGL is broken on Windows in windowed mode. I tried different APIs (SDL, glfw, SFML), all with the same result: although the frame rate is limited (and constantly around 16-17 ms according to CPU measurements on several 60 Hz settings that I tried), and the CPU actually slept big part of the time, frames are often skipped. Depending on the machine and CPU usage for things other than rendering, this can be as bad as effectively halving the frame rate. This problem does not seem to be related to drivers.
How to work with vsync on Windows with OpenGL in windowed mode or a similar effect with these properties (if I forgot something noticeable or if something is unreasonable, please comment):
- CPU can sleep most of the time
- No breaks
- No skipped frames (assuming the system is not overloaded)
- The CPU will know when the frame was actually shown.
DETAILS / SOME RESEARCH
When I googled opengl vsync stutteror opengl vsync frame dropsimilar requests, I found that many people have this problem (or very similar), but there seems to be no consistent solution to the real problem (many have not answered enough questions about gamedev stackexchange too, as well as many low-level messages effort).
: , (DWM), Windows, vsync. DWM, vsync, , (FOOTNOTE1). , vsync .
: , Linux, . ( ) OpenGL vsync .
, D3D OpenGL Windows ( vsync). vsync Windows ( , ( ) , - Intel + NVidia, , t , AMD/ATI).
, , Windows, , , , 3D-/ - , OpenGL , , CPU .
, , ,
while (true)
{
poll_all_events_in_event_queue();
process_things();
render();
}
, , . , , , (. ), , ( , ).
, , (.. , - 30 60 60 ). , 2- , Nyquist, , - (.. Windows OpenGL). , , , . , timeBeginPeriod .
(FOOTNOTE1) , - DWM ( vsync, , CPU ). , vsync .
, , , - ( ) ( - ) , ( , , , , glGetError), .
, , ( SFML, , , ).
. - ( ) , .
( , ):
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "OpenGL");
window.setVerticalSyncEnabled(true);
window.setActive(true);
int frame_counter = 0;
sf::RectangleShape rect;
rect.setSize(sf::Vector2f(10, 10));
sf::Clock clock;
while (true)
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
return 0;
}
}
++frame_counter;
if (frame_counter & 1)
{
glClearColor(0, 0, 0, 1);
}
else
{
glClearColor(60.0/255.0, 50.0/255.0, 75.0/255.0, 1);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#if 0
int fc_mod = frame_counter % 8;
int color_mod = fc_mod % 4;
for (int i = 0; i < 30; ++i)
{
rect.setPosition(fc_mod * 20 + 10, i * 20 + 10);
rect.setFillColor(
sf::Color(
(color_mod == 0 || color_mod == 3) ? 255 : 0,
(color_mod == 0 || color_mod == 2) ? 255 : 0,
(color_mod == 1) ? 155 : 0,
255
)
);
window.draw(rect);
}
#endif
int elapsed_ms = clock.restart().asMilliseconds();
if (elapsed_ms > 17 || elapsed_ms < 15)
{
std::cout << elapsed_ms << std::endl;
}
window.display();
}
return 0;
}
:
:
- Windows 10 x64 i7-4790K + GeForce 970 (, Linux) ( 60 )
- Windows 7 x64 i5-2320 + GeForce 560 ( 60 )
- Windows 10 x64 Intel Core2 Duo T6400 + GeForce 9600M GT (, Linux ) ( 60 )
- 2 , Windows 10 x64 7 x64 , " "
20170815
, :
explicit sleep ( SFML-, Sleep Windows API, , timeBeginPeriod ).
60 , 16 2/3 . QueryPerformanceCounter, .
17 , , . , ( ), , -. .
16 , , . , , , 17 , .
15 , . , . 1 15 .
, - concurrency vsync OpenGL .
Linux. : , . , , , , vsync. , - .
, , vsync ( , -, 2017 OpenGL).
20170816
"" 3D- ( obbg (https://github.com/nothings/obbg) ).
, . . / , .
, , . , obbg , ( , obbg ingame). , , ( , ). , , OpenGL , , . , - .
, - . , , , .
, OpenGL , obbg SDL, ( , , , ). "" obbg, , , . SDL ; , Visual Studio 2017, , . #if, .
https://github.com/bplu4t2f/sdl_test
, SDL D3D. , , , . , , .
, , D3D OpenGL ( ) - 17.0 17.2 ( ). OpenGL. OpenGL 15.0.. 17.0. , ( - ), OpenGL, , . ?
. , , .