/* AMD16bpc_FormattingShader.frag.txt -- RGBA16 output formatter * * This shader converts a HDR texture into a RGBA8 8bpc framebuffer * image, suitable for scanout by a AMD GPU in 64 bpp / 16 bpc mode. * It expects the RGB image data in the respective channels of * the texture, with values ranging from 0.0 - 1.0, remaps it into * the output data range of the GPU, then encodes the 16 bit values * into the red+green+blue channels of consecutive pixels. Each 16 bit * value is split into 8 Most significant bits and 8 least significant bits, * and these are stored in consecutive color components of pixels. This way, * two color components encode one color channel and one needs two consecutive * horizontal pixels in the framebuffer to encode one 64 bpp color pixel. * * This shader is intended for use as a plugin for the 'FinalOutputFormattingBlit' * chain of the Psychtoolbox-3 imaging pipeline. * * (c) 2014 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 uniform sampler2DRect Image; uniform float Prescale; uniform float halfFBWidth; void main() { float horizontalOffset; /* Get default texel read position (x,y): x is column, y is row of image. */ vec2 readpos = gl_FragCoord.xy; /* "Even" output rows encode right dual-display output, or nothing. */ if (mod(gl_FragCoord.y, 2.0) < 1.0) { /* Even row: Sample right half of input image on dual-display, or the void on single-display setup. */ horizontalOffset = halfFBWidth; } else { /* Odd row: Sample left half of input image on dual-display, all on single-display. */ horizontalOffset = 0.0; } /* Update the s (==column) component to read each pixel column twice, replicating it. */ readpos.s = horizontalOffset + ((readpos.s - mod(readpos.s, 2.0)) * 0.5); /* Due to skipping of every 2nd output row above, make sure the skip is discarded. */ readpos.t = (readpos.t - mod(readpos.t, 2.0)) * 0.5; /* Retrieve RGBA HDR input color value for a virtual pixel. */ vec4 incolor = texture2DRect(Image, readpos); /* Remap all color channels from 0.0 - 1.0 to 0 to 65535: */ /* Perform rounding for non-integral numbers and add a small epsilon to take numeric roundoff into account: */ vec3 index = floor(incolor.rgb * Prescale + 0.5) + 0.01; /* Compute high bytes (8 MSBs) for all color components. */ vec3 hibytes = floor(index / 256.0) / 255.0; /* Compute low bytes (8 LSBs) for color components. */ vec3 lobytes = mod(index, 256.0) / 255.0; gl_FragColor = vec4(0.0); /* Distribution of bytes into output pixel components is dependent */ /* on our output pixel location. Are we writing an even or odd pixel? */ if (mod(gl_FragCoord.x, 2.0) < 1.0) { /* Even output pixel: */ gl_FragColor.a = hibytes.g; gl_FragColor.r = lobytes.g; gl_FragColor.g = hibytes.b; gl_FragColor.b = lobytes.b; } else { /* Odd output pixel: */ gl_FragColor.a = 0.0; gl_FragColor.r = 0.0; gl_FragColor.g = hibytes.r; gl_FragColor.b = lobytes.r; } }