/* GenericLuminanceToRGBA8_FormattingShader.frag.txt -- Luminance output formatter * * This shader converts a HDR luminance texture into a RGBA8 8bpc framebuffer * image, suitable for display with a variety of high precision luminance * output devices. It expects the luminance image data in the red channel of * the texture, with values ranging from 0.0 - 1.0, remaps it into * the bpc bit data range of the device (max. 16 bpc), then breaks the * (up to 16 bit) integral luminance index value into a low byte index (8 LSB) * between 0 and 255, and a high byte index (up to 8 MSB) between 0 and up * 255. The (LSB,MSB) index pair is used as a 2D coordinate into a 2D RGBA8 * LUT texture of size 256 columns by up to 256 rows texels and the value * read from that LUT texture (a RGBA8 pixel) is written to the framebuffer. * * By encoding a proper LUT from 0 to 2^bpc-1 luminance indices into RGBA8 drive * pixels, one can drive luminance output devices of up to 16 bit luminance * resolution. Building of the LUT texture is usually done by PsychImaging.m. * * Please note that LUT based output conversion is usually not the most * efficient method, as it requires two texture lookups (1 dependend texture * lookup) per converted pixel. This requires large memory bandwidth and is * limited in speed by (relatively high) memory access latency. If possible * for a given output device it is better to encode the conversion algorithm * as a closed formula inside a specific shader for that device, e.g., like * done for the CRS Bits+ boxes, the ATI native 10bpc framebuffer, etc. * The speed of numeric computation of modern GPU's is higher than their ability * to access memory - and therefore to access lookup tables, so one can do * a lot of computation in the time it would take to fetch a single value * from a LUT! * * This LUT shader is a generic "catch all" to quickly support new devices * for which no specific output driver has been written yet. * * This shader is intended for use as a plugin for the 'FinalOutputFormattingBlit' * chain of the Psychtoolbox-3 imaging pipeline. * * (c)2007, 2008 by Mario Kleiner, part of PTB-3, licensed to you under MIT license. * See file License.txt in the Psychtoolbox root folder for the license. * */ #extension GL_ARB_texture_rectangle : enable /* The input Image - Usually from texture unit 0: */ uniform sampler2DRect Image; /* The LUT - Usually bound to texture unit 1: */ uniform sampler2DRect LUT; /* Maximum luminance index for device: Typically 2^bpc - 1 for given bit depths bpc: */ uniform float MaxIndex; /* Declare external function for luminance color conversion: */ float icmTransformColor1(float incolor); void main() { vec2 lutindex; /* Retrieve HDR/High precision input luminance value from RED channel: */ /* The same value is stored (replicated) in the GREEN and BLUE channels */ /* if this is a drawn luminance image, so choice of channel doesn't matter. */ /* We expect these values to be in 0.0 - 1.0 range. */ /* We add a small numerical 'epsilon' offset of 1e-7 to the fetched value. */ /* This is to account for small numerical differences between GPU's float */ /* storage format and CPU's double format. This is not strictly neccessary, */ /* but we do it to achieve identical results between GPU and CPU conversion */ /* to simplify validation/testing and intermix of CPU and GPU methods. */ float incolor = texture2DRect(Image, gl_TexCoord[0].st).r + 1e-7; /* Apply some color transformation (clamping, gamma correction etc.): */ incolor = icmTransformColor1(incolor); /* Remap 'incolor' from 0.0 - 1.0 range to range 0 - MaxIndex. Turn */ /* remapped value into integral value by floor()'ing to closest */ /* smaller or equal integral value: 'index' will be our linear index into the LUT. */ float index = floor(incolor * MaxIndex); /* Compute high byte (8 MSBs) of 2D texture lookup position: */ lutindex.y = floor(index / 256.0) + 0.5; /* Compute low byte (8 LSBs) of 2D texture lookup position: */ lutindex.x = floor(mod(index, 256.0)) + 0.5; /* Readout LUT texture at 2D location lutindex(x,y) to get final RGBA8 */ /* output pixel and write it to framebuffer: */ gl_FragColor = texture2DRect(LUT, lutindex); }