+ /* Build fragment program if needed */
+ vgl->program = 0;
+ vgl->local_count = 0;
+ if (supports_fp) {
+ char *code = NULL;
+
+ if (need_fs_yuv) {
+ /* [R/G/B][Y U V O] from TV range to full range
+ * XXX we could also do hue/brightness/constrast/gamma
+ * by simply changing the coefficients
+ */
+ const float matrix_bt601_tv2full[3][4] = {
+ { 1.1640, 0.0000, 1.4030, -0.7773 },
+ { 1.1640, -0.3440, -0.7140, 0.4580 },
+ { 1.1640, 1.7730, 0.0000, -0.9630 },
+ };
+ const float matrix_bt709_tv2full[3][4] = {
+ { 1.1640, 0.0000, 1.5701, -0.8612 },
+ { 1.1640, -0.1870, -0.4664, 0.2549 },
+ { 1.1640, 1.8556, 0.0000, -1.0045 },
+ };
+ const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
+ : matrix_bt601_tv2full;
+
+ /* Basic linear YUV -> RGB conversion using bilinear interpolation */
+ const char *template_yuv =
+ "!!ARBfp1.0"
+ "OPTION ARB_precision_hint_fastest;"
+
+ "TEMP src;"
+ "TEX src.x, fragment.texcoord[0], texture[0], 2D;"
+ "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
+ "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
+
+ "PARAM coefficient[4] = { program.local[0..3] };"
+
+ "TEMP tmp;"
+ "MAD tmp.rgb, src.xxxx, coefficient[0], coefficient[3];"
+ "MAD tmp.rgb, src.yyyy, coefficient[1], tmp;"
+ "MAD result.color.rgb, src.zzzz, coefficient[2], tmp;"
+ "END";
+ bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
+ vgl->fmt.i_chroma == VLC_CODEC_YV9;
+ if (asprintf(&code, template_yuv,
+ swap_uv ? 'z' : 'y',
+ swap_uv ? 'y' : 'z') < 0)
+ code = NULL;
+
+ for (int i = 0; i < 4; i++) {
+ float correction = i < 3 ? yuv_range_correction : 1.0;
+ for (int j = 0; j < 4; j++) {
+ vgl->local_value[vgl->local_count + i][j] = j < 3 ? correction * matrix[j][i] : 0.0;
+ }
+ }
+ vgl->local_count += 4;
+ }
+ if (code) {
+ // Here you have shaders
+ vgl->GenProgramsARB(1, &vgl->program);
+ vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
+ vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(code), (const GLbyte*)code);
+ if (glGetError() == GL_INVALID_OPERATION) {
+ /* FIXME if the program was needed for YUV, the video will be broken */
+#if 0
+ GLint position;
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);