title: sRGB correction for textures in OpenGL on iOS
body: <p>I am experiencing the issue described in <a href="http://www.arcsynthesis.org/gltut/Texturing/Tutorial%2016.html" rel="nofollow">this article</a> where the second color ramp is effectively being gamma-corrected <em>twice</em>, resulting in overbright and washed-out colors. This is in part a result of my using an sRGB framebuffer, but that is not the actual reason for the problem.</p>
  
  <p>I'm testing textures in my test app on iOS8, and in particular I am currently using a PNG image file and using <code>GLKTextureLoader</code> to load it in as a cubemap. </p>
  
  <p>By default, textures are treated NOT as being in sRGB space (which they are invariably saved in by the image editing software used to build the texture). </p>
  
  <p>The consequence of this is that Apple has made GLKTextureLoader do the <code>glTexImage2D</code> call for you, and they invariably are calling it with the <code>GL_RGB8</code> setting, whereas for actual correctness in future color operations we have to uncorrect the gamma in order to obtain linear brightness values in our textures for our shaders to sample. </p>
  
  <p>Now I can actually see the argument that it is not required of most mobile applications to be pedantic about color operations and color correctness as applied to advanced 3D techniques involving color blending. Part of the issue is that it's unrealistic to use the precious shared device RAM to store textures at any bit depth greater than 8 bits per channel, and if we read our JPG/PNG/TGA/TIFF and gamma-uncorrect its 8 bits of sRGB into 8 bits <em>linear</em>, we're going to degrade quality.</p>
  
  <p>So the process for most apps is just happily toss linear color correctness out the window, and just ignore gamma correction anyway and do blending in the SRGB space. This suits Angry Birds very well, as it is a game that has no shading or blending, so it's perfectly sensible to do all operations in gamma-corrected color space.</p>
  
  <p>So this brings me to the problem that I have now. I need to use <code>EXT_sRGB</code> and GLKit makes it easy for me to set up an sRGB framebuffer, and this works great on last-3-or-so-generation devices that are running iOS 7 or later. In doing this I address the dark and unnatural shadow appearance of an uncorrected render pipeline. This allows my lambertian and blinn-phong stuff to actually look good. It lets me store sRGB in render buffers so I can do post-processing passes while leveraging the improved perceptual color resolution provided by storing the buffers in this color space.</p>
  
  <p>But the problem now as I start working with textures is that it seems like I can't even use GLKTextureLoader as it was intended, as I just get a mysterious error (code 18) when I set the options flag for SRGB (GLKTextureLoaderSRGB). And it's impossible to debug as there's no source code to go with it. </p>
  
  <p>So I was thinking I could go build my texture loading pipeline back up with <code>glTexImage2D</code> and use <code>GL_SRGB8</code> to specify that I want to gamma-uncorrect my textures before I sample them in the shader. However a quick look at GL ES 2.0 docs reveals that GL ES 2.0 is not even sRGB-aware. </p>
  
  <p>At last I find the <code>EXT_sRGB</code> spec, which says </p>
  
  <pre><code>Add Section 3.7.14, sRGB Texture Color Conversion
  
  If the currently bound texture's internal format is one of SRGB_EXT or 
  SRGB_ALPHA_EXT the red, green, and blue components are converted from an
  sRGB color space to a  linear color space as part of filtering described in
  sections 3.7.7 and 3.7.8. Any alpha component is left unchanged.  Ideally,
  implementations should perform this color conversion on each sample prior
  to filtering but implementations are allowed to perform this conversion
  after filtering (though this post-filtering approach is inferior to 
  converting from sRGB prior to filtering).
  
  The conversion from an sRGB encoded component, cs, to a linear component,
  cl, is as follows.
  
          {  cs / 12.92,                 cs &lt;= 0.04045
     cl = {
          {  ((cs + 0.055)/1.055)^2.4,   cs &gt;  0.04045
  
  Assume cs is the sRGB component in the range [0,1]."
  </code></pre>
  
  <p>Since I've never dug this deep when implementing a game engine for desktop hardware (which I would expect color resolution considerations to be essentially moot when using render buffers of 16 bit depth per channel or higher) my understanding of how this works is unclear, but this paragraph does go some way toward reassuring me that I can have my cake and eat it too with respect to retaining all 8 bits of color information if I am to load in the textures using <code>SRGB_EXT</code> image storage format. </p>
  
  <p>Here in OpenGL ES 2.0 with this extension I can use <code>SRGB_EXT</code> or <code>SRGB_ALPHA_EXT</code> rather than the analogous <code>SRGB</code> or <code>SRGB8_ALPHA</code> from vanilla GL.</p>
  
  <p>My apologies for not presenting a simple answerable question. Let it be this one: Am I barking up the wrong tree here or are my assumptions more or less correct? Feels like I've been staring at these specs for far too long now. Another way to answer my question is if you can shed some light on the GLKTextureLoader error 18 that I get when I try to set the sRGB option. </p>
  
  <p>It seems like there is yet more reading for me to do as I have to decide whether to start to branch my code to get one codepath that uses GL ES 2.0 with EXT_sRGB, and the other using GL ES 3.0, which certainly looks very promising by comparing the documentation for <code>glTexImage2D</code> with other GL versions and appears closer to OpenGL 4 than the others, so I am really liking that ES 3 will be bringing mobile devices a lot closer to the API used on the desktop.</p>