I want to do something that is very trivial with OpenGL and GLFW: I want to scroll a 100x100 white filled rectangle from left to right and back again. The rectangle should be moved by 1 pixel per frame and the scrolling should be perfectly smooth. This is my code:
int main(void)
{
GLFWwindow* window;
int i = 0, mode = 0;
if(!glfwInit()) return -1;
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if(!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 640, 0, 480, -1, 1);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(1.0, 1.0, 1.0);
while(!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glRecti(i, 190, i + 100, 290);
glfwSwapBuffers(window);
glfwPollEvents();
if(!mode) {
i++;
if(i >= 539) mode = 1;
} else {
i--;
if(i <= 0) mode = 0;
}
}
glfwTerminate();
return 0;
}
On Mac OS X and Linux this code is working really fine. The scrolling is perfectly sync'ed with the vertical refresh and you cannot see any stuttering or flickering. It is really perfectly smooth.
On Windows, things are more difficult. By default, glfwSwapInterval(1) doesn't have any effect on Windows when desktop compositing is enabled. GLFW docs say that this has been done because enabling the swap interval with DWM compositing enabled can lead to severe jitter. This behaviour can be changed by compiling GLFW with GLFW_USE_DWM_SWAP_INTERVAL defined. In that case, the code above works really fine on Windows as well. The scrolling is perfectly sync'ed and there is no jitter. I tested it on a variety of different machines running XP, Vista, 7, and 8.
However, there has to be a very good reason that made the GLFW authors disable the swap interval on Windows by default so I suppose that there are many configurations where it will indeed lead to severe jitter. Maybe I was just lucky that none of my machines showed it. So defining GLFW_USE_DWM_SWAP_INTERVAL is not really a solution I can live with because there has to be a reason why it is disabled by default, although it somewhat escapes me that the GLFW team didn't come up with a nicer solution because as it stands now, GLFW programs aren't really portable because of this issue. Take the code above as an example: It will be perfectly sync'ed on Linux and OS X, but on Windows it will run at lightning speed. This somewhat defies GLFW's concept of portability in my eyes.
Given the situation that GLFW_USE_DWM_SWAP_INTERVAL cannot be used on Windows because the GLFW team explicitly warns about its use, I'm wondering what else I should do. The natural solution is of course a timer which measures the time and makes sure that glfwSwapBuffers() is not called more often than the monitor's vertical refresh rate.
However, this also is not as simple as it sounds since I cannot use Sleep() because this would be much too imprecise. Hence, I'd have to use a polling loop with QueryPerformanceCounter(). I tried this approach and it pretty much works but the CPU usage is of course up to 100% now because of the polling loop sleep. When using GLFW_USE_DWM_SWAP_INTERVAL, on the other hand, CPU usage is at a mere 1%.
An alternative would be to set up a timer that fires at regular intervals but AFAIK the precision of CreateTimerQueueTimer() is not very satisfying and probably doesn't yield perfectly sync'ed results.
To cut a long story short: I'd like to ask what is the recommended way of dealing with this problem? The example code above is of course just for illustration purposes. My general question is that I'm looking for a clean way to make glfwSwapBuffers() swap buffers in sync with the monitor's vertical refresh on Windows. On Linux and Mac OS X this is already working fine but on Windows there is the problem with severe jitter that the GLFW docs talk about (but which I don't see here).
I'm still somewhat puzzled that GLFW doesn't provide an inbuilt solution to this problem and pretty much leaves it up to the programmer to workaround this. I'm still a newbie to OpenGL but from my naive point of view, I think that having a function that swaps buffers in sync with vertical refresh is a feature of fundamental importance so it escapes me why GLFW doesn't have it on Windows.
So once again my question is: How can I workaround the problem that glfwSwapInterval() doesn't work correctly on Windows? What is the suggested approach to solve this problem? Is there a nicer way than using a poll timer that will hog the CPU?
I think your issue has solved itself by a strange coincidence in timing. This commit has been added to GLFW's master branch just a few days ago, and it is removing the GLFW_USE_DWM_SWAP_INTERVAL because they are now using DWM's DWMFlush() API to do the syncing when DWM is in use. The changelog for this commit includes:
[Win32] Removed GLFW_USE_DWM_SWAP_INTERVAL compile-time option
[Win32] Bugfix: Swap interval was ignored when DWM was enabled
So probably grabbing the newest git HEAD for GLFW is all you need to do.
Related
I have an performance issue with P5.js when rendered in Chrome, but not other browsers. I get around 10-15 fps in Chrome, even when tested with a simple moving ellipse. I've tried restarting my computer, doing a clean install of Chrome, updating the libraries, but nothing worked. When performing, my CPU usage goes up quite a bit (2.5 Ghz i7) to around 50% usage. Chrome dev tools doesn't really help either, showing "program" being the culprit for CPU usage.
The weirdest thing is that a couple weeks ago, everything waas going smooth and no problem was ever encountered.
Thus I wondered if any of you guys ever had such an issue or knows what's going on. Thanks!
Edit: Here's the simple a simple testing code that runs very poorly on my machine.
function setup() {
createCanvas(windowWidth,windowHeight);
}
let a = 0;
let b = 0;
function draw() {
background(0);
fill(255);
ellipse(a,b,200);
a += 1;
b += 1;
}
First of all after 4 hours of debugging I have no problem with my code. But I'm curious why I had issue that I had.
I created fullscreen window with d3d11 rendering. Problem occurred when I tried to alt-tab window and didn't have Present() in my loop (I simply found this issue before implementing rendering function). In that case after minimizing window Red and Blue channels on my screen were swapped (yes, literally).
It took me long time to find because I suspected my swap chain or window itself (sdl). Can you help me find the reason of this bug- for educational purposes?
This usually is due to a graphics driver bug with RGBA swap chains. You can try updating your driver (run Windows Update). But to improve compatibility you can change your swap chain surface format to BGRA (specifically, B8G8R8A8_UNORM). As long as you are just doing normal rendering (and not doing anything fancy like UpdateSubresource directly to the back buffer), you should be able to leave everything else as-is and it will render correctly.
I just hit something particularly hard to debug when doing some pretty intensive rendering with Canvas2D. I use all kinds of things, from globalCompositeOperation to multiple off-screen canvases, with some drawImage magic in-between.
It works perfectly fine and smooth on :
Chrome (26) [OSX 10.7.5]
Safari (6.0.2) [OSX 10.7.5]
Firefox (Both 18 and 20 Aurora) [OSX 10.7.5]
Chrome (24) [Windows 7]
Firefox (12) [Windows 7]
Chromium (24) [Archlinux, Gnome 3]
EDIT: Added tests for Windows 7. Strangely enough, it works for FF12 (I had an old version on my dual boot) but there's a definite performance hit after upgrading to FF18. It's not as bad on Windows as it is on Linux though, and the same version on OSX works flawlessly. Regression maybe?
For some reason, on Firefox and Linux (I tried both 18 and 20 Aurora), I have bad rendering performances when dragging and rendering at the same time.
If I fire-and-forget an animation, it is on par with Chrome/Safari, but if I drag and render, I often end up only seeing the end frame after I release the drag.
Neither requestAnimationFrame nor a direct rendering on the mouse event handler work.
After profiling, the reported timings for the rendering parts are well within the range of acceptable (up to 100ms at the absolute worst), and definitely do not correspond to what I see on the screen.
I tried reducing the load by removing some stuff, ending up with reported render times under 15ms, but what I saw didn't change.
What baffles me is that it works almost everywhere else except with Firefox on Linux. Any idea as to where I should look, a bug report or a solution to my problem?
I have fully switched to Chrome on linux because of this issue. It stems from the old 2d rendering engine they are using called Cairo, which is old and out-dated. Azure was to replace this engine and they have it done basically all the platforms except linux.
http://blog.mozilla.org/joe/2011/04/26/introducing-the-azure-project/
https://bugzilla.mozilla.org/show_bug.cgi?id=781731
I think I know where you should look based on this:
If I fire-and-forget an animation, it is on par with Chrome/Safari, but if I drag and render, I often end up only seeing the end frame after I release the drag.
This is probably a double-buffering bug with Firefox on linux.
Canvas implementations have double-buffering built in. You can see it in action on any browser in a simple example like this one: http://jsfiddle.net/simonsarris/XzAjv/ (which uses a setTimeout vs extra work to illustrate that clearing does not happen right away)
The implementations try to delay all rendering by rendering it to an internal bitmap, and then all at once (at the next pause) render it to the canvas. This stops the "flickering" effect when clearing a canvas before redrawing a scene, which is good.
But it seems there's a plain old bug in the Linux Firefox. During your drag and render it seems to not be updating the canvas, probably in an attempt to buffer, but seems to be doing so when it should not be. This would explain why it works in fire-and-forget scenarios.
So I think a bug report is in order. I haven't got any linux machines lying around so I can't reproduce it and submit something myself to be certain though, sorry.
This is in reply to a comment: You could, during the mouse move, dispatch the drawing portion to a tiny timer.
For instance:
// The old way
theCanvas.addEventListener('mousemove', function() {
// if we're dragging and are redrawing
drawingCode();
}, false);
// The new way
theCanvas.addEventListener('mousemove', function() {
// if we're dragging and are redrawing
// in 1 millisecond, fire off drawing code
setTimeout(function() { drawingCode(); }, 1);
}, false);
There isn't such a method, its totally hidden. What you could do is, during mouse move, dispatch
There is SDL_WM_ToggleFullScreen. However, on Mac, its implementation destroys the OpenGL context, which destroys your textures along with it. Ok, annoying, but I can reload my textures. However, when I reload my textures after toggling, it crashes on certain textures inside of a memcpy being called by glTexImage2D. Huh, it sure didn't crash when I loaded those textures the first time around. I even try deleting all my textures before the toggle, but I get the same result.
As a test, I reload textures without toggling fullscreen, and the textures reload fine. So, toggling the fullscreen does something funny to OpenGL. (And, by "toggling", I mean going in either direction: windowed->fullscreen or fullscreen->windowed - I get the same results.)
As an alternative, this code seems to toggle fullscreen as well:
SDL_Surface *surface = SDL_GetVideoSurce();
Uint32 flags = surface->flags;
flags ^= SDL_FULLSCREEN;
SDL_SetVideoMode(surface->w, surface->h, surface->format->BitsPerPixel, flags);
However, calling SDL_GetError after this code says that the "Invalid window" error was set during the SDL_SetVideoMode. And if I ignore it and try to load textures, there is no crashing, but my textures don't show up either (perhaps OpenGL is just immediately returning from glTexImage2D without actually doing anything). As a test, at startup time, I try calling SDL_SetVideoMode twice in a row to perform a toggle right before I even load my textures the first time. In that particular case, the textures do actually show up. Huh, what?
I am using SDL 1.3.0-6176 (posted on the SDL website January 7, 2012).
Update:
My texture uploading code is below (nothing surprising here). For clarification, this application (including the code below) is already working without any issues as a finished application for iOS, Android, PSP, and Windows. Windows is the only other version, other than Mac, that is using SDL under the hood.
unsigned int Texture::init(const void *data, int width, int height)
{
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
return textureID;
}
it crashes on certain textures inside of a memcpy being called by glTexImage2D.
This shouldn't happen. There's some bug somewhere, either in your code or that of the OpenGL implementation. And I'd say it's yours. So please post your texture allocation and upload code for us to see.
However, on Mac, its implementation destroys the OpenGL context, which destroys your textures along with it.
Yes, unfortunately this is the way how it works on MacOS X. And due to the design of its OpenGL driver model, there's litte you can do about it (did I mention that MacOS X sucks; oh yes, I did. On occasion. Like over a hundred times). The same badly designed driver model also makes MacOS X so slow in catching up with OpenGL development.
I wrote a free game a few years ago: http://www.walkover.org. For the lobby and menus, it uses normal dialogs like win32. When the actual game starts it uses OpenGL.
Now, on Windows 7, when the actual game starts, it switches windows aero glass off and switches it back on when the game is over.
Is there something I can do to prevent this from happening? Some special flags that keep the glass on if it is on? (For newer, I have been using DirectX and this doesn#t happen there.) Maybe some (new) flag I have to specify somewhere?
I'm using this pixelformatdescriptor:
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
32, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
0, // 32-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
This problem is caused by all of the following:
Windows 7
OpenGL
Creating a window that matches your screen rect exactly (Fullscreen)
Calling Swap Buffers for the second time
Old graphics card drivers
I have the same problem and I tested 2 AAA game engines that use OpenGL and can confirm they both had the same problem. DirectX seems unaffected.
This means your window create is fine, it is not a code problem.
I would recommend updating your graphics card drivers to solve the problem.
A short term work around I found was to create a window that is 1 pixel larger than your screen resolution (on either width or height)
This tricks windows into not detecting that you have gone into fullscreen and doesn't trigger the problem.
I think this can happen if you create an OpenGL rendering context that is incompatible with Aero Glass. IIRC one of the cases that can cause this is if you create a window using 16-bit colour. Aero Glass can't render in 16-bit colour, so for some technical reason, Windows has to completely disable Aero Glass (even though only your app is using it). Try using 32-bit colour.
There might be other settings that disable it for similar reasons. In short, double check all the settings you're creating OpenGL with, and think "would Aero Glass switch off if the desktop was switched to this mode?".
Not sure exactly what you're doing that's causing this, but it's probably just as well -- Microsoft's OpenGL implementation in Windows 7 is not exactly perfect, to put it nicely. In fact, in most of my OpenGL code, I've taken to explicitly turning off the DWM. Otherwise, bugs in Microsoft's implementation basically stop it from working at all. Though I can work around that some extent in other ways, the performance is so poor it renders the code essentially unusable anyway (I haven't done serious measurements, but at an immediate guess I'd say at least 5:1 performance loss).
I once encountered a problem in my application that GDI couldn't read OpenGL-rendered window contents when trying to do BitBlt from the window DC. This was back then when Vista just came out. Using PFD_SUPPORT_GDI would work around this, but it would also disable Aero. I guess this issue made a lot of old apps broken, so they forced it to be on in some cases. Not sure what's your case here. I would bet on a driver stub issue.
Just my own limited experience with OpenGL, Aero and GDI.