| Summary: | SDL_GL_SetSwapInterval not working on MacOS 10.12 | ||
|---|---|---|---|
| Product: | SDL | Reporter: | Patric Ljung <patric.ljung> |
| Component: | video | Assignee: | Ryan C. Gordon <icculus> |
| Status: | RESOLVED ABANDONED | QA Contact: | Sam Lantinga <slouken> |
| Severity: | blocker | ||
| Priority: | P2 | CC: | amaranth72 |
| Version: | 2.0.5 | Keywords: | target-2.0.6 |
| Hardware: | x86_64 | ||
| OS: | macOS 10.12 | ||
I can't reproduce this issue (tested with macOS 10.12.5, using a Radeon Pro 460). Ryan, can you reproduce this on your Mac? Hi guys,
thanks for looking into this. Since I reported it I found some MacOS ways of, presumably, setting the swap interval as well, namely through the CGLContext.
Unfortunately, that does not work either, as done in the code snippet below. Via a key event I change it during run-time but I still get about 200+ FPS (yep, this is Intel integrated Iris OpenGL engine). Sample output provided after code.
I tested the same method in another GLUT-based application (Apples deprecated GLUT version) and there it properly works, it toggles between steady 60 FPS and ~200 FPS when enabled/disabled.
void update_swap_interval(app_data_t & app)
{
#if 1
// Use Vsync
if (SDL_GL_SetSwapInterval(app.swap_interval) < 0) {
fprintf(stderr, "Warning: Unable to set VSync! SDL Error: %s\n", SDL_GetError());
}
else {
printf("Successfully set SDL Swap Interval to %d\n", SDL_GL_GetSwapInterval());
}
#ifdef __APPLE__
CGLContextObj cgl_context = CGLGetCurrentContext();
if (cgl_context == 0) {
printf("Failed to retrieve CGL Context\n");
}
else {
int current_swap_int = 0;
CGLError res;
res = CGLGetParameter(cgl_context, kCGLCPSwapInterval,
¤t_swap_int);
if (res != kCGLNoError) {
printf("Failed to retrieve current swap interval, error = %d\n", res);
}
else {
printf("Current Swap Interval by CGL Context: %d\n",
current_swap_int);
}
res = CGLSetParameter(cgl_context, kCGLCPSwapInterval, &app.swap_interval);
if (res != kCGLNoError) {
printf("Failed to set swap interval through CGL Context, error = %d\n",
res);
}
else {
printf("Succesfully set swap interval %d through CGL Context\n",
app.swap_interval);
}
}
#endif
#endif
}
Example output:
Successfully set SDL Swap Interval to 1
Current Swap Interval by CGL Context: 1
Succesfully set swap interval through CGL Context
keymod = 00000000
Successfully set SDL Swap Interval to 0
Current Swap Interval by CGL Context: 0
Succesfully set swap interval through CGL Context
keymod = 00000000
Successfully set SDL Swap Interval to 1
Current Swap Interval by CGL Context: 1
Succesfully set swap interval through CGL Context
keymod = 00000000
Successfully set SDL Swap Interval to 0
Current Swap Interval by CGL Context: 0
Succesfully set swap interval through CGL Context
This is working as-is on my 10.12.6 MacBook Pro with both the Intel HD 4000 integrated GPU and the Nvidia 650M discrete GPU. I think this is a driver bug. That being said: the docs for this say in this code... https://hg.libsdl.org/SDL/file/e3797888c6f1/src/video/cocoa/SDL_cocoaopengl.m#l345 ...that "value" should be a long, not a GLint. However, Apple's own example code uses GLint. Maybe some drivers get a bogus value here in 64-bit builds? It's also work noting that this goes through Cocoa for us, but Patric's code uses CoreGraphics. Possible this demonstrates a driver bug too. The Cocoa path does not report an error when setting the swap interval; the message used returns void, which is why SDL reports success. Maybe we should call -[NSOpenGLContext getValues:forParameter] and see if the value actually set? I would need Patric to experiment on his machine, if possible, though. The thing that sets the value... https://developer.apple.com/documentation/appkit/nsopenglcontext/1436199-setvalues?language=objc The value we set (specifies a "long") ... https://developer.apple.com/documentation/appkit/nsopenglcpswapinterval?language=objc The way we get values (_also_ says "long" but takes a GLint*)... https://developer.apple.com/documentation/appkit/nsopenglcontext/1436189-getvalues?language=objc --ryan. Going to mark this one as WAITING, because I would need Patric to explore this on his machine, but I'm inclined to say it's a driver bug and ignore it unless it becomes more widespread. --ryan. I'd like to try out what you are suggesting, but I have so far not written a single line of Objective-C, which I believe is the API-language. From what I've read it should be possible to mix C/C++ with Objective-C and it is on my todo list.
But before that, I would like to point out I have tried the previously posted code both with SDL and with Apples deprecated GLUT framework. In GLUT it works properly, but the same code is not resulting in a change with SDL. So if it's a driver bug I am inclined to believe there's something more to it, it works with GLUT.
Im my case I use CMake to setup my build files (.xcodeproj files) and there should be a way to have it include .m or .mm compilation units. But, again, haven't done it yet.
The idea would be to declare a function in C++ and define it in an .mm file (Objective-C++) and call the necessary Cocoa set/get functions there, as you suggest. Just to simplify cross-platform support.
Would you be able to fill out the missing pieces here? And possibly how to setup the compilation in CMake file.
// MySwapInterval.mm
#include "MySwapInterval.hh" // C++ declaration of My[Set/Get]SwapInterval()
// HELP: -- Include Cocoa stuff for NSOpenGLContext (setValue/getValue)
#import <OpenGL/CGLContext.h> // Not really sure what to import for NSOpenGLContext
int MySetSwapInterval(int interval)
{
// I am kind of guessing the Objective-C code/syntax here.
// HELP: Don't know what context should be, should it not be "class" method?
CGLContexObj glcontext = [??context?? CGLContextObj];
GLint swapInt = interval;
// Set the swap interval
[glcontext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
// Get the resulting swap interval
[glcontext getValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
return (int)swapInt;
}
Some more comments: When retrieving current swap interval from both SDL and Core Graphics it accurately reports the swap interval that was set, but it doesn't affect reality.
Managed to get CMake to include and build my .mm file. But I am not doing things right in that function. Getting a segfault at setValues. I am, however, ignorant about the difference between the CGLContextObj, SDL_GL_Context, and NSOpenGLContext.
Here's my current code, taking SDL_GL_Context in _glcontext (as void *).
#import <OpenGL/CGLContext.h>
#import <Cocoa/Cocoa.h>
int mySetSwapInterval(void * _glcontext, int interval)
{
// HELP: Don't know what context should be, should it not be "class" method?
GLint swapInt = interval;
NSOpenGLContext * oglcontext = (NSOpenGLContext *)_glcontext;
CGLContextObj glcontext = [oglcontext CGLContextObj];
// Set the swap interval -- CRASHES on the following line!
[(id)glcontext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
// Get the resulting swap interval
[(id)glcontext getValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
return (int)swapInt;
}
I'm unable to reproduce this either. I modified testgl2.c to toggle swap interval when the '1' key is pressed, and I see the cube spinning madly until I press 1, then it goes at a nice and sedate pace until I press 1 again after which it starts spinning madly again. The behavior doesn't appear to be affected by moving windows over the testgl window to partially or completely occlude it. Hello, and sorry if you're getting dozens of copies of this message by email. We are closing out bugs that appear to be abandoned in some form. This can happen for lots of reasons: we couldn't reproduce it, conversation faded out, the bug was noted as fixed in a comment but we forgot to mark it resolved, the report is good but the fix is impractical, we fixed it a long time ago without realizing there was an associated report, etc. Individually, any of these bugs might have a better resolution (such as WONTFIX or WORKSFORME or INVALID) but we've added a new resolution of ABANDONED to make this easily searchable and make it clear that it's not necessarily unreasonable to revive a given bug report. So if this bug is still a going concern and you feel it should still be open: please feel free to reopen it! But unless you respond, we'd like to consider these bugs closed, as many of them are several years old and overwhelming our ability to prioritize recent issues. (please note that hundred of bug reports were sorted through here, so we apologize for any human error. Just reopen the bug in that case!) Thanks, --ryan. |
I'm trying to force GL to lock with Swap Interval but to no avail. I have another GLUT-based application that solidly renders at 60 Hz. No matter what interval I specify I get that it has been properly set but still renders at whatever rate it can, no error is reported. I deem this blocking as SDL cannot be used unless it can be VSynced. Am I doing something wrong? MacOS 10.12.3, MacBook Pro Late 2013, Intel Iris GL. GL Version: 4.1 INTEL-10.22.29 GL Vendor: Intel Inc. Example code: // Order of inits done prior to setting SwapInterval // SDL_Init // SDL_CreateWindow // SDL_GL_SetAttribute // SDL_GL_CreateContext // GLEW_Init // Use Vsync if (SDL_GL_SetSwapInterval(4) < 0) { fprintf(stderr, "Warning: Unable to set VSync! SDL Error: %s\n", SDL_GetError()); } else { printf("Successfully set Swap Interval to %d\n", SDL_GL_GetSwapInterval()); } Running the application gives me the following (with any interval 1 - 5) Successfully set Swap Interval to 4