// Texture IDs #if PIXFMT == V4L2_PIX_FMT_SBGGR8 || PIXFMT == V4L2_PIX_FMT_SGBRG8 || \ PIXFMT == V4L2_PIX_FMT_SGRBG8 || PIXFMT == V4L2_PIX_FMT_SRGGB8 || \ PIXFMT == V4L2_PIX_FMT_SBGGR10 || PIXFMT == V4L2_PIX_FMT_SGBRG10 || \ PIXFMT == V4L2_PIX_FMT_SGRBG10 || PIXFMT == V4L2_PIX_FMT_SRGGB10 || \ PIXFMT == V4L2_PIX_FMT_SBGGR12 || PIXFMT == V4L2_PIX_FMT_SGBRG12 || \ PIXFMT == V4L2_PIX_FMT_SGRBG12 || PIXFMT == V4L2_PIX_FMT_SRGGB12 || \ PIXFMT == V4L2_PIX_FMT_SBGGR16 || PIXFMT == V4L2_PIX_FMT_SGBRG16 || \ PIXFMT == V4L2_PIX_FMT_SGRBG16 || PIXFMT == V4L2_PIX_FMT_SRGGB16 || \ PIXFMT == V4L2_PIX_FMT_GREY || PIXFMT == V4L2_PIX_FMT_Y16 || \ PIXFMT == V4L2_PIX_FMT_Y16_BE || PIXFMT == V4L2_PIX_FMT_Z16 || \ PIXFMT == V4L2_PIX_FMT_Y10 || PIXFMT == V4L2_PIX_FMT_Y12 uniform highp usampler2D tex; #else uniform sampler2D tex; #endif uniform sampler2D ytex; uniform sampler2D uvtex; uniform sampler2D utex; uniform sampler2D vtex; in vec2 vs_TexCoord; out vec4 fs_FragColor; // YUV (aka Y'CbCr) to R'G'B' matrices const mat3 yuv2rgb = mat3( #if YCBCRENC == V4L2_YCBCR_ENC_SMPTE240M // Old obsolete HDTV standard. Replaced by REC 709. // SMPTE 240M has its own luma coefficients 1.0, 1.0, 1.0, 0.0, -0.2253, 1.8270, 1.5756, -0.4768, 0.0 #elif YCBCRENC == V4L2_YCBCR_ENC_BT2020 // BT.2020 luma coefficients 1.0, 1.0, 1.0, 0.0, -0.1646, 1.8814, 1.4719, -0.5703, 0.0 #elif YCBCRENC == V4L2_YCBCR_ENC_601 || YCBCRENC == V4L2_YCBCR_ENC_XV601 // These colorspaces all use the BT.601 luma coefficients 1.0, 1.0, 1.0, 0.0, -0.344, 1.773, 1.403, -0.714, 0.0 #else // The HDTV colorspaces all use REC 709 luma coefficients 1.0, 1.0, 1.0, 0.0, -0.1870, 1.8556, 1.5701, -0.4664, 0.0 #endif ); // Various colorspace conversion matrices that transfer the source chromaticities // to the sRGB/Rec.709 chromaticities const mat3 colconv = mat3( #if COLSP == V4L2_COLORSPACE_SMPTE170M || COLSP == V4L2_COLORSPACE_SMPTE240M // Current SDTV standard, although slowly being replaced by REC 709. // Uses the SMPTE 170M aka SMPTE-C aka SMPTE RP 145 conversion matrix. 0.939536, 0.017743, -0.001591, 0.050215, 0.965758, -0.004356, 0.001789, 0.016243, 1.005951 #elif COLSP == V4L2_COLORSPACE_470_SYSTEM_M // Old obsolete NTSC standard. Replaced by REC 709. // Uses the NTSC 1953 conversion matrix and the Bradford method to // compensate for the different whitepoints. 1.4858417, -0.0251179, -0.0272254, -0.4033361, 0.9541568, -0.0440815, -0.0825056, 0.0709611, 1.0713068 #elif COLSP == V4L2_COLORSPACE_470_SYSTEM_BG // Old obsolete PAL/SECAM standard. Replaced by REC 709. // Uses the EBU Tech. 3213 conversion matrix. 1.0440, 0, 0, -0.0440, 1, -0.0119, 0, 0, 1.0119 #elif COLSP == V4L2_COLORSPACE_OPRGB 1.3982832, 0, 0, -0.3982831, 1, -0.0429383, 0, 0, 1.0429383 #elif COLSP == V4L2_COLORSPACE_DCI_P3 // Uses the Bradford method to compensate for the different whitepoints. 1.1574000, -0.0415052, -0.0180562, -0.1548597, 1.0455684, -0.0785993, -0.0025403, -0.0040633, 1.0966555 #elif COLSP == V4L2_COLORSPACE_BT2020 1.6603627, -0.1245635, -0.0181566, -0.5875400, 1.1329114, -0.1006017, -0.0728227, -0.0083478, 1.1187583 #else // Identity matrix 1.0 #endif ); void main() { const float texl_w = 1.0 / tex_w; const float texl_h = 1.0 / tex_h; float alpha = 0.0; vec2 xy = vs_TexCoord; float xcoord = floor(xy.x * tex_w); float ycoord = floor(xy.y * tex_h); bool xeven = mod(xcoord, 2.0) == 0.0; bool yeven = mod(ycoord, 2.0) == 0.0; vec3 yuv; vec3 rgb; #if FIELD == V4L2_FIELD_SEQ_TB xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5; #elif FIELD == V4L2_FIELD_SEQ_BT xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0; #endif #if IS_RGB // Bayer pixel formats #if PIXFMT == V4L2_PIX_FMT_SBGGR8 || PIXFMT == V4L2_PIX_FMT_SBGGR10 || PIXFMT == V4L2_PIX_FMT_SBGGR12 || PIXFMT == V4L2_PIX_FMT_SBGGR16 uvec4 urgb; vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h); urgb.r = texture(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r; urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r; urgb.b = texture(tex, cell).r; #elif PIXFMT == V4L2_PIX_FMT_SGBRG8 || PIXFMT == V4L2_PIX_FMT_SGBRG10 || PIXFMT == V4L2_PIX_FMT_SGBRG12 || PIXFMT == V4L2_PIX_FMT_SGBRG16 uvec4 urgb; vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h); urgb.r = texture(tex, vec2(cell.x, cell.y + texl_h)).r; urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r; urgb.b = texture(tex, vec2(cell.x + texl_w, cell.y)).r; #elif PIXFMT == V4L2_PIX_FMT_SGRBG8 || PIXFMT == V4L2_PIX_FMT_SGRBG10 || PIXFMT == V4L2_PIX_FMT_SGRBG12 || PIXFMT == V4L2_PIX_FMT_SGRBG16 uvec4 urgb; vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h); urgb.r = texture(tex, vec2(cell.x + texl_w, cell.y)).r; urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r; urgb.b = texture(tex, vec2(cell.x, cell.y + texl_h)).r; #elif PIXFMT == V4L2_PIX_FMT_SRGGB8 || PIXFMT == V4L2_PIX_FMT_SRGGB10 || PIXFMT == V4L2_PIX_FMT_SRGGB12 || PIXFMT == V4L2_PIX_FMT_SRGGB16 uvec4 urgb; vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h); urgb.b = texture(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r; urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r; urgb.r = texture(tex, cell).r; #elif PIXFMT == V4L2_PIX_FMT_RGB32 || PIXFMT == V4L2_PIX_FMT_XRGB32 || PIXFMT == V4L2_PIX_FMT_ARGB32 || \ PIXFMT == V4L2_PIX_FMT_RGB444 || PIXFMT == V4L2_PIX_FMT_XRGB444 || PIXFMT == V4L2_PIX_FMT_ARGB444 vec4 cell = texture(tex, xy); #if V4L2_PIX_FMT_ARGB444 || PIXFMT == V4L2_PIX_FMT_ARGB32 alpha = cell.r; #endif rgb.rgb = cell.gba; #elif PIXFMT == V4L2_PIX_FMT_BGR32 || PIXFMT == V4L2_PIX_FMT_XBGR32 || PIXFMT == V4L2_PIX_FMT_ABGR32 || \ PIXFMT == V4L2_PIX_FMT_BGRX444 || PIXFMT == V4L2_PIX_FMT_BGRA444 || \ PIXFMT == V4L2_PIX_FMT_XBGR555 || PIXFMT == V4L2_PIX_FMT_ABGR555 || \ PIXFMT == V4L2_PIX_FMT_RGBX555 || PIXFMT == V4L2_PIX_FMT_RGBA555 vec4 cell = texture(tex, xy); #if PIXFMT == V4L2_PIX_FMT_ABGR32 || PIXFMT == V4L2_PIX_FMT_BGRA444 || PIXFMT == V4L2_PIX_FMT_RGBA555 || PIXFMT == V4L2_PIX_FMT_ABGR555 alpha = cell.a; #endif rgb.rgb = cell.bgr; #elif PIXFMT == V4L2_PIX_FMT_RGBX32 || PIXFMT == V4L2_PIX_FMT_RGBA32 || \ PIXFMT == V4L2_PIX_FMT_RGBX444 || PIXFMT == V4L2_PIX_FMT_RGBA444 || \ PIXFMT == V4L2_PIX_FMT_RGB555 || PIXFMT == V4L2_PIX_FMT_XRGB555 || PIXFMT == V4L2_PIX_FMT_ARGB555 || \ PIXFMT == V4L2_PIX_FMT_BGRX555 || PIXFMT == V4L2_PIX_FMT_BGRA555 vec4 cell = texture(tex, xy); #if PIXFMT == V4L2_PIX_FMT_RGBA32 || PIXFMT == V4L2_PIX_FMT_RGBA444 || PIXFMT == V4L2_PIX_FMT_ARGB555 || PIXFMT == V4L2_PIX_FMT_BGRA555 alpha = cell.a; #endif rgb.rgb = cell.rgb; #elif PIXFMT == V4L2_PIX_FMT_BGRX32 || PIXFMT == V4L2_PIX_FMT_BGRA32 || \ PIXFMT == V4L2_PIX_FMT_XBGR444 || PIXFMT == V4L2_PIX_FMT_ABGR444 vec4 cell = texture(tex, xy); #if PIXFMT == V4L2_PIX_FMT_BGRA32 || PIXFMT == V4L2_PIX_FMT_ABGR444 alpha = cell.r; #endif rgb.rgb = cell.abg; #elif PIXFMT == V4L2_PIX_FMT_GREY rgb.rgb = vec3(float(texture(tex, xy).r) / 255.0); #elif PIXFMT == V4L2_PIX_FMT_Y10 rgb.rgb = vec3(float(texture(tex, xy).r) / 1023.0); #elif PIXFMT == V4L2_PIX_FMT_Y12 rgb.rgb = vec3(float(texture(tex, xy).r) / 4095.0); #elif PIXFMT == V4L2_PIX_FMT_Y16 || PIXFMT == V4L2_PIX_FMT_Z16 rgb.rgb = vec3(float(texture(tex, xy).r) / 65535.0); #elif PIXFMT == V4L2_PIX_FMT_Y16_BE uint low = texture(tex, xy).r >> 8; uint high = (texture(tex, xy).r & 0xFFu) << 8; rgb.rgb = vec3(float(high | low) / 65535.0); #else vec4 color = texture(tex, xy); // RGB pixel formats with an alpha component #if PIXFMT == V4L2_PIX_FMT_ARGB555 || PIXFMT == V4L2_PIX_FMT_ARGB555X || \ PIXFMT == V4L2_PIX_FMT_RGBA555 || PIXFMT == V4L2_PIX_FMT_ABGR555 || \ PIXFMT == V4L2_PIX_FMT_BGRA555 alpha = color.a; #endif #if PIXFMT == V4L2_PIX_FMT_BGR666 vec3 frgb = floor(color.rgb * 255.0); frgb.r = floor(frgb.r / 64.0) + mod(frgb.g, 16.0) * 4.0; frgb.g = floor(frgb.g / 16.0) + mod(frgb.b, 4.0) * 16.0; frgb.b = floor(frgb.b / 4.0); rgb = frgb / 63.0; #elif PIXFMT == V4L2_PIX_FMT_BGR24 rgb = color.bgr; #else rgb = color.rgb; #endif #endif #if PIXFMT == V4L2_PIX_FMT_SBGGR8 || PIXFMT == V4L2_PIX_FMT_SGBRG8 || \ PIXFMT == V4L2_PIX_FMT_SGRBG8 || PIXFMT == V4L2_PIX_FMT_SRGGB8 rgb = vec3(urgb) / 255.0; #elif PIXFMT == V4L2_PIX_FMT_SBGGR10 || PIXFMT == V4L2_PIX_FMT_SGBRG10 || \ PIXFMT == V4L2_PIX_FMT_SGRBG10 || PIXFMT == V4L2_PIX_FMT_SRGGB10 rgb = vec3(urgb) / 1023.0; #elif PIXFMT == V4L2_PIX_FMT_SBGGR12 || PIXFMT == V4L2_PIX_FMT_SGBRG12 || \ PIXFMT == V4L2_PIX_FMT_SGRBG12 || PIXFMT == V4L2_PIX_FMT_SRGGB12 rgb = vec3(urgb) / 4095.0; #elif PIXFMT == V4L2_PIX_FMT_SBGGR16 || PIXFMT == V4L2_PIX_FMT_SGBRG16 || \ PIXFMT == V4L2_PIX_FMT_SGRBG16 || PIXFMT == V4L2_PIX_FMT_SRGGB16 rgb = vec3(urgb) / 65535.0; #endif #if QUANT == V4L2_QUANTIZATION_LIM_RANGE rgb -= 16.0 / 255.0; rgb *= 255.0 / 219.0; #endif #else // IS_RGB #if PIXFMT == V4L2_PIX_FMT_YUYV vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y)); yuv.r = xeven ? luma_chroma.r : luma_chroma.b; yuv.gb = luma_chroma.ga; #elif PIXFMT == V4L2_PIX_FMT_YVYU vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y)); yuv.r = xeven ? luma_chroma.r : luma_chroma.b; yuv.gb = luma_chroma.ag; #elif PIXFMT == V4L2_PIX_FMT_UYVY vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y)); yuv.r = xeven ? luma_chroma.g : luma_chroma.a; yuv.gb = luma_chroma.rb; #elif PIXFMT == V4L2_PIX_FMT_VYUY vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y)); yuv.r = xeven ? luma_chroma.g : luma_chroma.a; yuv.gb = luma_chroma.br; #elif PIXFMT == V4L2_PIX_FMT_NV16 || PIXFMT == V4L2_PIX_FMT_NV16M || \ PIXFMT == V4L2_PIX_FMT_NV12 || PIXFMT == V4L2_PIX_FMT_NV12M yuv.r = texture(ytex, xy).r; if (xeven) { yuv.g = texture(uvtex, xy).r; yuv.b = texture(uvtex, vec2(xy.x + texl_w, xy.y)).r; } else { yuv.g = texture(uvtex, vec2(xy.x - texl_w, xy.y)).r; yuv.b = texture(uvtex, xy).r; } #elif PIXFMT == V4L2_PIX_FMT_NV61 || PIXFMT == V4L2_PIX_FMT_NV61M || \ PIXFMT == V4L2_PIX_FMT_NV21 || PIXFMT == V4L2_PIX_FMT_NV21M yuv.r = texture(ytex, xy).r; if (xeven) { yuv.g = texture(uvtex, vec2(xy.x + texl_w, xy.y)).r; yuv.b = texture(uvtex, xy).r; } else { yuv.g = texture(uvtex, xy).r; yuv.b = texture(uvtex, vec2(xy.x - texl_w, xy.y)).r; } #elif PIXFMT == V4L2_PIX_FMT_NV24 yuv.r = texture(ytex, xy).r; yuv.g = texture(uvtex, xy).r; yuv.b = texture(uvtex, xy).g; #elif PIXFMT == V4L2_PIX_FMT_NV42 yuv.r = texture(ytex, xy).r; yuv.g = texture(uvtex, xy).g; yuv.b = texture(uvtex, xy).r; #elif PIXFMT == V4L2_PIX_FMT_YUV555 vec4 color = texture(tex, xy); alpha = color.a; yuv = color.rgb; #elif PIXFMT == V4L2_PIX_FMT_YUV444 || PIXFMT == V4L2_PIX_FMT_YUV32 || \ PIXFMT == V4L2_PIX_FMT_XYUV32 || PIXFMT == V4L2_PIX_FMT_AYUV32 vec4 color = texture(tex, xy); #if PIXFMT == V4L2_PIX_FMT_AYUV32 alpha = color.r; #endif yuv.r = color.g; yuv.g = color.b; yuv.b = color.a; #elif PIXFMT == V4L2_PIX_FMT_VUYA32 || PIXFMT == V4L2_PIX_FMT_VUYX32 vec4 color = texture(tex, xy); #if PIXFMT == V4L2_PIX_FMT_VUYA32 alpha = color.a; #endif yuv.r = color.b; yuv.g = color.g; yuv.b = color.r; #elif PIXFMT == V4L2_PIX_FMT_YUV565 yuv = texture(tex, xy).rgb; #elif PIXFMT == V4L2_PIX_FMT_YUV422P || PIXFMT == V4L2_PIX_FMT_YUV420 || PIXFMT == V4L2_PIX_FMT_YVU420 || \ PIXFMT == V4L2_PIX_FMT_YUV420M || PIXFMT == V4L2_PIX_FMT_YVU420M || \ PIXFMT == V4L2_PIX_FMT_YUV422M || PIXFMT == V4L2_PIX_FMT_YVU422M || \ PIXFMT == V4L2_PIX_FMT_YUV444M || PIXFMT == V4L2_PIX_FMT_YVU444M yuv = vec3(texture(ytex, xy).r, texture(utex, xy).r, texture(vtex, xy).r); #endif #if IS_HSV vec4 color = texture(tex, xy); #if PIXFMT == V4L2_PIX_FMT_HSV32 color = color.gbar; #endif // From http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl float hue = color.r; #if HSVENC == V4L2_HSV_ENC_180 hue = (hue * 256.0) / 180.0; #endif vec3 c = vec3(hue, color.g, color.b); vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); rgb = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); #else // IS_HSV yuv.gb -= 0.5; #endif #if QUANT != V4L2_QUANTIZATION_FULL_RANGE || YCBCRENC == V4L2_YCBCR_ENC_XV601 || YCBCRENC == V4L2_YCBCR_ENC_XV709 /* * xv709 and xv601 have full range quantization, but they still * need to be normalized as if they were limited range. But the * result are values outside the normal 0-1 range, which is the * point of these extended gamut encodings. */ const vec3 scale = vec3(255.0 / 219.0, 255.0 / 224.0, 255.0 / 224.0); const vec3 offset = vec3(16.0 / 255.0, 0.0, 0.0); yuv -= offset; yuv *= scale; #endif #if YCBCRENC == V4L2_YCBCR_ENC_BT2020_CONST_LUM // BT.2020_CONST_LUM luma coefficients float y = yuv.r; float u = yuv.g; float v = yuv.b; float b = u <= 0.0 ? y + 1.9404 * u : y + 1.5816 * u; float r = v <= 0.0 ? y + 1.7184 * v : y + 0.9936 * v; float lin_r = (r < 0.081) ? r / 4.5 : pow((r + 0.099) / 1.099, 1.0 / 0.45); float lin_b = (b < 0.081) ? b / 4.5 : pow((b + 0.099) / 1.099, 1.0 / 0.45); float lin_y = (y < 0.081) ? y / 4.5 : pow((y + 0.099) / 1.099, 1.0 / 0.45); float lin_g = lin_y / 0.6780 - lin_r * 0.2627 / 0.6780 - lin_b * 0.0593 / 0.6780; float g = (lin_g < 0.018) ? lin_g * 4.5 : 1.099 * pow(lin_g, 0.45) - 0.099; rgb = vec3(r, g, b); #elif !IS_HSV rgb = yuv2rgb * yuv; #endif #endif // !IS_RGB // Convert non-linear R'G'B' to linear RGB, taking into account the // colorspace. #if XFERFUNC == V4L2_XFER_FUNC_SMPTE240M // Old obsolete HDTV standard. Replaced by REC 709. // This is the transfer function for SMPTE 240M #define XFER(c) (((c) < 0.0913) ? (c) / 4.0 : pow(((c) + 0.1115) / 1.1115, 1.0 / 0.45)) rgb = vec3(XFER(rgb.r), XFER(rgb.g), XFER(rgb.b)); #elif XFERFUNC == V4L2_XFER_FUNC_SRGB // This is used for sRGB as specified by the IEC FDIS 61966-2-1 standard #define XFER(c) (((c) < -0.04045) ? -pow((-(c) + 0.055) / 1.055, 2.4) : \ (((c) <= 0.04045) ? (c) / 12.92 : pow(((c) + 0.055) / 1.055, 2.4))) rgb = vec3(XFER(rgb.r), XFER(rgb.g), XFER(rgb.b)); #elif XFERFUNC == V4L2_XFER_FUNC_OPRGB // Avoid powers of negative numbers rgb = max(rgb, vec3(0.0)); rgb = pow(rgb, vec3(2.19921875)); #elif XFERFUNC == V4L2_XFER_FUNC_DCI_P3 // Avoid powers of negative numbers rgb = max(rgb, vec3(0.0)); rgb = pow(rgb, vec3(2.6)); #elif XFERFUNC == V4L2_XFER_FUNC_SMPTE2084 const vec3 m1 = vec3(1.0 / ((2610.0 / 4096.0) / 4.0)); const vec3 m2 = vec3(1.0 / (128.0 * 2523.0 / 4096.0)); const vec3 c1 = vec3(3424.0 / 4096.0); const vec3 c2 = vec3(32.0 * 2413.0 / 4096.0); const vec3 c3 = vec3(32.0 * 2392.0 / 4096.0); // Avoid powers of negative numbers rgb = max(rgb, vec3(0.0)); rgb = pow(rgb, m2); // The factor 100 is because SMPTE-2084 maps to 0-10000 cd/m^2 // whereas other transfer functions map to 0-100 cd/m^2. rgb = pow(max(rgb - c1, vec3(0.0)) / (c2 - rgb * c3), m1) * 100.0; #elif XFERFUNC != V4L2_XFER_FUNC_NONE // All others use the transfer function specified by REC 709 #define XFER(c) (((c) <= -0.081) ? -pow(((c) - 0.099) / -1.099, 1.0 / 0.45) : \ (((c) < 0.081) ? (c) / 4.5 : pow(((c) + 0.099) / 1.099, 1.0 / 0.45))) rgb = vec3(XFER(rgb.r), XFER(rgb.g), XFER(rgb.b)); #endif // Convert the given colorspace to the REC 709/sRGB colorspace. All colors are // specified as linear RGB. #if COLSP == V4L2_COLORSPACE_SMPTE170M || COLSP == V4L2_COLORSPACE_SMPTE240M || \ COLSP == V4L2_COLORSPACE_470_SYSTEM_M || COLSP == V4L2_COLORSPACE_470_SYSTEM_BG || \ COLSP == V4L2_COLORSPACE_OPRGB || COLSP == V4L2_COLORSPACE_DCI_P3 || \ COLSP == V4L2_COLORSPACE_BT2020 rgb = colconv * rgb; #endif // Convert linear RGB to non-linear R'G'B', assuming an sRGB display colorspace. #define XFER_SRGB(c) (((c) < -0.0031308) ? -1.055 * pow(-(c), 1.0 / 2.4) + 0.055 : \ (((c) <= 0.0031308) ? (c) * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055)) rgb = vec3(XFER_SRGB(rgb.r), XFER_SRGB(rgb.g), XFER_SRGB(rgb.b)); fs_FragColor = vec4(rgb, alpha); }