1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
/* 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);
}
|