Advertisement

Gamma changes when fullscreen (SDL2, OpenGL)

Started by July 02, 2019 06:45 PM
10 comments, last by bodigy 5 years, 2 months ago

Hi gamedevs!

I've been googling my issue for days now, nothing comes up that would solve it. People have similar problems, but this one seems unique to me?!

To get to the point, here's what I have:

  • custom C++ engine, doing the baby steps, for now. I can render 2D sprites with transparency properly
  • OpenGL (4.4 core) with SDL2, glew
  • 2 SRGB Frambuffers, I render to the 1st, then post-effects to the 2nd, then blit it to the default FBO
  • Windows 10 desktop PC, 4k screen (well, two of them, different types)
  • GeForce GTX 1050 Ti, latest drivers
  • SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
  • glEnable(GL_FRAMEBUFFER_SRGB);

So, the problem:

In windowed mode, the gamma is fine. Whenever I go "full screen" (not even exclusive mode, just borderless, i.e. SDL_WINDOW_FULLSCREEN_DESKTOP), the screen suddenly becomes too dark. Here's the fun part: if I then press the volume up/down multimedia key, then while the Win10 overlay is showing, the gamma becomes correct!! But the moment when the volume overlay is gone, boom, darker screen again. While it's "switching", I can see pink-ish, green-ish artifacts for about 1/10 of a second. Switching back to windowed, it's fine again. Screenshots done while fullscreen look fine.

Now, I have no idea what causes this - is it SDL, OpenGL, Windows, GPU drivers, or my monitor (both of them do this)? I'm hoping someone can help figure this out. I'll be eternally grateful, since this is making me pull my hair out. Disclaimer: I'm not that experienced in this area (graphics programming, GPUs), my greatest achievement was a deferred renderer playground (it used WinApi - not SDL).

Help me please!!

Adam B

 

EDIT: Forgot to mention that I've checked many settings already. In NVIDIA Control Panel, I don't have anything suspicious, under "Adjust desktop color settings", it's "Use NVIDIA settings". Nothing that would indicate any kind of overrides. Windows 10's Game Mode ON/OFF doesn't make a difference. Game bar is OFF.

5 hours ago, bodigy said:

Screenshots done while fullscreen look fine

So does that mean that even if you see dark pictures on your screens, if you take a screenshot, they presumably have the right brightness ?

5 hours ago, bodigy said:

is it SDL, OpenGL, Windows, GPU drivers, or my monitor (both of them do this)?

If this is SDL, then switching to another GL window layer will make this disappear. Something like glfw could be a good choice.

If this is OpenGL, this is hard to say like this. Talk about your post-treatment. What are you doing and how ?

What happens if you resize to some size in between your default resolution and fullscreen ?

What happens if you don't use SRGB framebuffer ?

Where in your pipeline do you use your SRGB rendering ?

Finally, provide as much as accurate and pertinent information.

Advertisement
7 hours ago, _Silence_ said:

So does that mean that even if you see dark pictures on your screens, if you take a screenshot, they presumably have the right brightness ?

Correct.

7 hours ago, _Silence_ said:

If this is SDL, then switching to another GL window layer will make this disappear. Something like glfw could be a good choice.

If I find out that it's caused by SDL, I'll definitely look for an alternative. But until then I wouldn't want to waste time on that. I'd rather develop my game :)

7 hours ago, _Silence_ said:

If this is OpenGL, this is hard to say like this. Talk about your post-treatment. What are you doing and how ?

Sorry, I didn't think my pipeline details were relevant for this. See below.

7 hours ago, _Silence_ said:

What happens if you resize to some size in between your default resolution and fullscreen ?

What happens if you don't use SRGB framebuffer ?

Where in your pipeline do you use your SRGB rendering ?

Any window size that doesn't cover the entire screen works fine. Borderless or not.

I just tried this morning to remove every mention of SRGB in my code, the colors / brightness got messed up as expected, but the windowed vs. fullscreen issue remained. In windowed it was too bright, and in fullscreen it "looked correct". But still inconsistent. So SRGB doesn't really seem to be the problem here. I'm suspecting some weird Windows or Nvidia feature, but can't figure out what.

Setup is pretty basic. Let's say my screen is 4k and I render in 1080p. In this case, I have 2 FBOs (1080p), both with a single (S)RGB attachment. I render (quad) sprites to the first one. Then I do a full-screen post-FX pass and render it to the second one. Just some chromatic aberration (I know, I know) and film grain, but I don't think that's relevant. Then I blit the 1080p buffer to the default framebuffer (4k). I don't need exclusive fullscreen mode, hence this solution - which, as far as I know, e.g. Valve games use as well. In earlier versions I didn't do glBlitFramebuffer but rendered directly to the default FBO, and still had the same problem.

7 hours ago, _Silence_ said:

Finally, provide as much as accurate and pertinent information.

Apologies, I thought I provided enough, about OS, GPU, etc. But you had some good questions already, so thank you!

SDL has the ability to mess with gamma correction, through SDL_SetWindowGammaRamp and SDL_SetWindowBrightness (which calls SDL_SetWindowGammaRamp).  So here is my hypothesis:

  • Either you have called SDL_SetWindowGammaRamp with an incorrect color ramp, or you haven't called SDL_SetWindowGammaRamp and the default color ramp is incorrect for your purposes.
  • SDL is always trying to set the global screen gamma, but it is only succeeding when it has exclusive access to the screen.  This means a full-screen window with no overlay on top.

To test this hypothesis, try calling SDL_SetWindowGammaRamp with some different values.  If my hypothesis is correct, this will change the gamma in full-screen mode (where it is currently too dark) and have no effect otherwise.

If my hypothesis is correct, then you can probably fix this problem by calling SDL_SetWindowGammaRamp with the correct gamma ramp.

3 hours ago, bodigy said:

If I find out that it's caused by SDL, I'll definitely look for an alternative. But until then I wouldn't want to waste time on that. I'd rather develop my game :)

It's not about a waste of time. It's about ensuring a thing, which, regarding other posts, might be the cause of your issues. Having a fallback is not a waste of time, to my opinion.

2 hours ago, a light breeze said:

If my hypothesis is correct, then you can probably fix this problem by calling SDL_SetWindowGammaRamp with the correct gamma ramp.

Thank you, sounds interesting, I'll try it out when I get home!

12 minutes ago, _Silence_ said:

It's not about a waste of time. It's about ensuring a thing, which, regarding other posts, might be the cause of your issues. Having a fallback is not a waste of time, to my opinion.

Right, but currently I also use SDL for input handling, so it'll be some work to switch to glfw. That's why I don't want to do it (for now) if I don't have to.

Advertisement

I'm about 90% sure I know what the problem is here. Considering that OpenGL doesn't really have APIs to enter an exclusive fullscreen mode, all the graphics drivers out there will go ahead and enter fullscreen exclusive mode for you when they detect that you've entered borderless windowed (i.e. full screen window, no border, nothing on top of you). Once your window's not in focus or not on top anymore, they'll leave fullscreen exclusive mode.

So, probably the gamma is just changing because of the fullscreen exclusive transition. You can validate using PresentMon. The present mode will change when the gamma changes if my hypothesis is correct. Either run it logging to a file in the background, or run it live on a second monitor.

You could try an older/newer version of SDL2.

Since you're learning, I would recommend just making do with a large viewport for now. Things like this have a way of resolving themselves or you figuring it out somewhere else down the line. Dealing with issues like this isn't much of a learning experience (It could be I guess?) and it can halt any progress that you were making prior.

🙂🙂🙂🙂🙂<←The tone posse, ready for action.

14 hours ago, SoldierOfLight said:

I'm about 90% sure I know what the problem is here. Considering that OpenGL doesn't really have APIs to enter an exclusive fullscreen mode, all the graphics drivers out there will go ahead and enter fullscreen exclusive mode for you when they detect that you've entered borderless windowed (i.e. full screen window, no border, nothing on top of you). Once your window's not in focus or not on top anymore, they'll leave fullscreen exclusive mode.

So, probably the gamma is just changing because of the fullscreen exclusive transition. You can validate using PresentMon. The present mode will change when the gamma changes if my hypothesis is correct. Either run it logging to a file in the background, or run it live on a second monitor.

Never heard of PresentMon, great tool, thanks! I ran it, and "PresentMode" indeed is different when it's running fullscreen with no overlays. Windowed, it says "Composed: Flip", fullscreen "Hardware Composed: Independent Flip". I'll take a look at the results in more detail when I get home, but I think we're getting closer to an answer! (Next question will be; why the brightness change and how to fix it :))

8 hours ago, fleabay said:

You could try an older/newer version of SDL2.

Since you're learning, I would recommend just making do with a large viewport for now. Things like this have a way of resolving themselves or you figuring it out somewhere else down the line. Dealing with issues like this isn't much of a learning experience (It could be I guess?) and it can halt any progress that you were making prior.

Good advice! But, it also leaves a lurking feeling that... you know... "I still have an annoying, unresolved issue - how can I build on buggy stuff like this?"

On 7/3/2019 at 10:55 AM, a light breeze said:

SDL has the ability to mess with gamma correction, through SDL_SetWindowGammaRamp and SDL_SetWindowBrightness (which calls SDL_SetWindowGammaRamp).  So here is my hypothesis:

  • Either you have called SDL_SetWindowGammaRamp with an incorrect color ramp, or you haven't called SDL_SetWindowGammaRamp and the default color ramp is incorrect for your purposes.
  • SDL is always trying to set the global screen gamma, but it is only succeeding when it has exclusive access to the screen.  This means a full-screen window with no overlay on top.

To test this hypothesis, try calling SDL_SetWindowGammaRamp with some different values.  If my hypothesis is correct, this will change the gamma in full-screen mode (where it is currently too dark) and have no effect otherwise.

If my hypothesis is correct, then you can probably fix this problem by calling SDL_SetWindowGammaRamp with the correct gamma ramp.

I tried this - both `SDL_SetWindowGammaRamp`  and `SDL_SetWindowBrightness`, with a test value of 2.0. The effect is exactly the opposite of what I needed / expected. If my game is running in windowed mode, the entire screen becomes brighter, as in, including everything on screen, other windows, the taskbar etc.. But fullscreen, it's still the same brightness (too dark) - so still even darker than normal. SDL_SetWindowGammaRamp seems to have no effect when fullscreen.

This topic is closed to new replies.

Advertisement