Skip to main content
New Participant
June 16, 2015

SRGB and SDK 0.6.0.0

I am wondering if there is any documentation available stating how the compositor is handling SRGB in the new SDK 0.6.0.0. Should the application be creating eye render targets that are linear or sRGB? I would assume they should be linear targets (so in D3D11 I am using DXGI_FORMAT_R8G8B8A8_UNORM) so that any math that is performed during the distortion process is performed correctly.

However, I am getting some strange results that make me think otherwise. There is no reference that I have been able to find in the developer document about sRGB, so if someone can make a clear statement about what should be used, then it would be very helpful.

Thanks in advance for any clarification you can provide.

    30 replies

    Inspiring
    November 4, 2015
    Ok, having done a reboot, I can now aquire two 8-Bit SwapTextureSets. Can't reproduce it again.
    Inspiring
    November 4, 2015
    But if Bruce is on his way cleaning the little bugs in the SDK, the SDK 0.8beta has some outdated references to OVR_CAPI_Util.h and OVR_StereoProjection.h not even needed to build - but these references moved to the Extras directory and are still referenced with their old location by the VS2010 project. This leads to a constantly dirty solution trying to rebuild each end every time run.
    Inspiring
    November 4, 2015
    Now that DX is working, I have trouble with Ambient Occlusion in OpenGL, because general enabling of "glEnable(GL_FRAMEBUFFER_SRGB)" leads to errors. But disabling it after ovrSubmitFrame before the next Ambient Occlusion is calculated, is as if SRGB Framebuffer has never been enabled due to the threading the present operation is not time related to ovrSubmitFrame. Wasn't it possible to let the Runtime enabling this by itself while the texture is rendered to the Oculus Screen? Did anybody with OpenGL knowledge think about this before implementing? This really becomes a matrix of ridiculous bugs were one can either have A correct with B false, or A correct and B correct with C false...
    Inspiring
    November 5, 2015
    Any news on the correct OpenGL textures format request when generating SwapChains? I mean GL_SRGB_ALPHA8 does only exist in the Oculus-Documentation but not in the OpenGL-World! Any assumptions that it might be GL_SRGB8_ALPHA8 don't get to the desired result, but you don't know if it is because of an Runtime bug or a false assumption...

    I did a workaround for OpenGL/Oculus-Runtime using 32bpc-Textures in OpenGL but a manual with values actually existing would be highly appreciable! Even the SDKs-Source does not help here, since it states equally wrong - best guess is something like Oculus World Demo were GL_SRGB8_ALPHA8 is used.
    Inspiring
    November 5, 2015
    Can you post the code that your trying, and then explain what the incorrect result actually is? You're asking a few different things here, and I just want to make sure I clearly understand what the problem is.
    AMD Ryzen 7 1800X | MSI X370 Titanium | G.Skill 16GB DDR4 3200 | EVGA SuperNOVA 1000 | Corsair Hydro H110i Gigabyte RX Vega 64 x2 | Samsung 960 Evo M.2 500GB | Seagate FireCuda SSHD 2TB | Phanteks ENTHOO EVOLV
    Inspiring
    November 6, 2015
    Sorry, there is no concrete code that fails to post here, code is perfectly fine anyways - it is the OVR API that is broken! Also no codesample, because we are writing a Plugin for a complex 3D Environment were we don't have all the source code for our selves. Like the code were Ambient Occlusion is done. Not having the codebase is why It is not possible for us to just glDisable(GL_FRAMEBUFFER_SRGB) just before Ambient Occlusion.

    We have just the chance to either leave our methods with glEnable(GL_FRAMEBUFFER_SRGB), but this leads to horrible rendering errors on parts not expecting it enabled like AO. If we glDisable(GL_FRAMEBUFFER_SRGB) when we leave, the Async thread performing writes in the Oculus Rift SDK also runs into disabled sRGB resulting in rendering to dark pictures to the rift.

    It would be perfectly ok, if we could just tell the OVR API weather it should write with or without sRBG. But instead of a reliable Flag in the API, it expects us to communicate with it by having the OpenGL state set to either enable or disable GL_FRAMEBUFFER_SRGB globally. The correct handling for OVR API expects us to leave it on for a sRGB correct rendering, while the plugins environment expects us to leave our method with GL_FRAMEBUFFER_SRGB disabled.

    This, in our complex environment, can either be done correct for the rest of the environment, or for the OVR SDK - but not for both! Due to the async nature of the SDK the GL_FRAMEBUFFER_SRGB state while our code is active has no effect on the OVR SDK - it is just a matter how we leave it! A simple flag could solve it, since the OVR Runtime could enable or disable it for its own (sRGB) write just as it is needed by itself, not forcing a general application state.

    I have done a workaround, but it is stupid I have to do tricks like this. Remember the guys who had an error with to light picture? It was because they did internal framebuffer writes with sRGB enabled, while the OVR SDK did a second framebuffer write with sRGB enabled, lightening up the picture a second time. Since we have to leave our methods in the render loop with glDisable(GL_FRAMEBUFFER_SRGB) the OVR SDK can not perform sRGB writes. But we do an internal framebuffer copy - doing it with enabled GL_FRAMEBUFFER_SRGB does an sRGB transform, then we disable it again. This way we avoid the other engine errors and the picture becomes not too bright.

    The way the OVR API is designed, sRGB write can not be done by the OVR SDK since it relays on the general OpenGL state, but it would be so easy to let it the OVR SDK do, if only it would not want the general state to be left either on or off and use a simple flag while SwapTextureSet creation or SubmitFrame instead.

    There are other tricks involved in the workaround that may not be desired by our environment also, but at this point it is at least working. What kind of OpenGL Noob did the API, since it should be a matter of course not relaying on a opengl state to be left enabled or disabled?! This is such a lousy API behavior, it will predictably force errors somewhere - please tell me this part of bad API design was not John Carmack's idea, it would destroy illusions about him...
    New Participant
    November 7, 2015
    Hi thewhiteambit,

    Your understanding of what glEnable(GL_FRAMEBUFFER_SRGB) does is incorrect. It modifies the fragment-shader-output into frame buffer while your own application's draw calls are being executed by GL. The OVR SDK does nothing with it. Once your app sends those render targets (i.e. eye textures) over to the OVR SDK, they are actually treated as sRGB-aware DirectX resources so there is no knowledge of what the GL_FRAMEBUFFER_SRGB state is on the SDK side.

    In your application, you can set your frame buffer, call glEnable(GL_FRAMEBUFFER_SRGB), do all your rendering into the eye textures, and then glDisable(GL_FRAMEBUFFER_SRGB) as soon as it's done rendering the eye texture. Then, assuming your AO pass is rendering into a separate frame buffer, it will take the new sRGB setting and use it for the subsequent draw calls.

    Feel free to respond if that suggestion does not seem to work because I'd like to see you resolve this issue. Worst case scenario would be to emulate sRGB conversions in the shader output, but that does not come for-free, and would be best used as a last resort.
    Inspiring
    November 7, 2015
    Ok, if the OVR SDK is doing nothing with the GL_FRAMEBUFFER_SRGB flag by itself when rendering, what you describe is exactly how my "workaround" is doing it right now. I thought the OVR SDK also needs the GL_FRAMEBUFFER_SRGB flag set, so that distortion rendering to the real rifts frontbuffer can apply linear to sRGB transform. But if that is not how it works, this would explain some of the things being strange to me.

    We have the picture calculated by our rendering environment in two textures (left, right), but can not make the ovr textures from the SwapTextureSet to our real (primary) rendertargets, so we just blit it from the one texture to another and apply sRGB in this step only. If it is ok for the OVR SDK to disable GL_FRAMEBUFFER_SRGB flag because it does not depend on it - great!

    Only thing remaining strange is, that 8bpc textures don't get sRGB treatment when copying to the SwapTextureSet, this only seems to work for non sRGB aware source formats. Our 8bpc-source-texture is sRGB aware, and does not resolve when copyed to the SwapTextureSet. Our 32pbc-source-texture is not sRGB aware and gets the sRGB treatment when copyed to the SwapTextureSet. Any ideas how to treat the 8bpc-source-textures correct so they dont end up being viewed to dark?
    Meta Employee
    November 10, 2015
    I don't know exactly how you're copying the contents of the texture from one to the other, but I wouldn't be surprised that the copy engine is also doing the sRGB conversion... or alternatively it's NOT doing the conversion even though you might want it. If you don't care about the extreme accuracy of your colors, you could apply a pow(1.0/2.2) on the output of the shader, and that will brighten up your colors to compensate for the original sRGB conversion. Obviously this wouldn't be ideal, but it can get you going nevertheless.

    The proper way to do sRGB correct rendering would be to mark your input textures with their appropriate sRGB formats. For example, if they're DXT/S3TC compressed, then GL provides formats like GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT. When sampling a texture with this format, the shader sampler will automatically do the sRGB-to-linear conversion for you.
    Inspiring
    November 10, 2015
    "volgaksoy" wrote:
    I don't know exactly how you're copying the contents of the texture from one to the other, but I wouldn't be surprised that the copy engine is also doing the sRGB conversion...


    I use glBlitFramebuffer​, that is working with sRGB transform for float32 but not with uint8 formats. At this point this could also be a nVidia driver bug with OpenGL.


    or alternatively it's NOT doing the conversion even though you might want it. If you don't care about the extreme accuracy of your colors, you could apply a pow(1.0/2.2)


    or use real sRGB transform, definitely not the problem...


    on the output of the shader, and that will brighten up your colors to compensate for the original sRGB conversion. Obviously this wouldn't be ideal, but it can get you going nevertheless.


    ...the problem with this solution is, I am not in any shader involved here. I could easyly add another screen quad draw with a shader just solving this, even skip the glBlitFramebuffer for it. But I would love to avoid this kind of lousy workarounds.


    The proper way to do sRGB correct rendering would be to mark your input textures with their appropriate sRGB formats.


    What can not be done since the input textures are received by the environment. Maybe there is access to it in OpenGL, so they can be marked and unmarked back to the original environments state. Could be a good sanitation for falsely marked uint8-textures. Is there any possibility to give the textures the right sRGB-mark in OpenGL, as there is with the ovrSwapTextureSetD3D11_Typeless trick for DirectX?


    For example, if they're DXT/S3TC compressed, then GL provides formats like GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT. When sampling a texture with this format, the shader sampler will automatically do the sRGB-to-linear conversion for you.


    But what if they are in simple R8G8B8A8_UINT and not marked sRGB but they should be? how to get a cheap sRGB-Blit transform without adding workarounds like dedicated shaders - were I will probably end up ;)