Swapchain format sRGB/RGB (OpenGL + Quest)

I have a problem with using swapchains on Quest (although Oculus PC implementation is almost the same here). It doesn’t matter what format I use (GL_RGBA8 or GL_SRGB8_ALPHA8) as it gives the same result, ie. the final image is brighten up. This is unless I explicitly convert gamma → linear in the shader which is a hack.

I guess that for OpenGLES it works this way as the image is always converted accordingly to the target surface (fragment shader is assumed to output linear, for RGB it is stored then in linear space, for sRGB it is stored in gamma space). But when it is processed further, it is always treated as linear and converted to gamma.

On PC it’s a bit better as you can use GL_SRGB8_ALPHA8 target to render without the conversion (disabled GL_FRAMEBUFFER_SRGB), making the result seem to be stored darker than it should and with forced conversion it gets to the right values.

Did anyone run into this issue with OpenXR+OpenGL on Quest when implementing native support?

From what I know, Unity forces to use linear space when using OpenXR which sounds again like a hack rather than a proper approach.

Hmm, have you seen https://developer.oculus.com/resources/color-management-guide/ ?

Thank you. Yes, I’ve seen it but I think that the issue might be that my shaders are doing calculations in sRGB. Which might be the cause of the bug. It’s my fault.

I’ll reply to my problem with more detailed info and a simple workaround.

“Solved” it. Or I should rather say: “hacked it”.

The reason why it was not working was that all the calculations (and colours and everything) that I have in my game are in sRGB/gamma space. The shaders should work in linear space. I learned properly about the difference well into the development and decided to keep it the way it was and… forgot about it.

The simplest workaround I found is to disable GL_FRAMEBUFFER_SRGB. I was not aware that it works with OpenGLES, although the default behaviour is different in OpenGL and OpenGLES. In OpenGLES it is automatically assumed it should do the conversion, in OpenGL you have to be explicit about it. I decided to do it explicitly for both.

The proper solution would be to fix the source of the problem - do the calculations in linear space. This would fix issues with blending colours - doing calculations/blending sRGB will darken the result although if you have lots of subtle blends, like me, you may not notice it.