From 0965bcee4367e23d306804963c79c628315dbb15 Mon Sep 17 00:00:00 2001 From: reimar Date: Wed, 7 Jun 2006 13:24:54 +0000 Subject: Reworked YUV2RGB fragment program setup in preparation for upcoming patches git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@18620 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libvo/gl_common.c | 209 ++++++++++++++++++++++++++++++++++-------------------- libvo/gl_common.h | 19 ++++- libvo/vo_gl.c | 17 +++-- libvo/vo_gl2.c | 3 +- 4 files changed, 165 insertions(+), 83 deletions(-) diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 25cb11e96a..3d4a6c346c 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -607,65 +607,105 @@ static void glSetupYUVCombinersATI(float uvcos, float uvsin) { EndFragmentShader(); } +static const char *bilin_filt_template = + "TEX yuv.%c, fragment.texcoord[%c], texture[%c], %s;"; + static const char *yuv_prog_template = - "!!ARBfp1.0\n" - "OPTION ARB_precision_hint_fastest;" "PARAM ycoef = {%.4f, %.4f, %.4f};" "PARAM ucoef = {%.4f, %.4f, %.4f};" "PARAM vcoef = {%.4f, %.4f, %.4f};" "PARAM offsets = {%.4f, %.4f, %.4f};" - "PARAM gamma = {%.4f, %.4f, %.4f};" - "TEMP res, y, u, v;" - "TEX y, fragment.texcoord[0], texture[0], %s;" - "MAD res, y, ycoef, offsets;" - "TEX u, fragment.texcoord[1], texture[1], %s;" - "MAD res, u, ucoef, res;" - "TEX v, fragment.texcoord[2], texture[2], %s;" - "MAD result.color, v, vcoef, res;" + "TEMP res;" + "MAD res.rgb, yuv.rrrr, ycoef, offsets;" + "MAD res.rgb, yuv.gggg, ucoef, res;" + "MAD result.color.rgb, yuv.bbbb, vcoef, res;" "END"; static const char *yuv_pow_prog_template = - "!!ARBfp1.0\n" - "OPTION ARB_precision_hint_fastest;" "PARAM ycoef = {%.4f, %.4f, %.4f};" "PARAM ucoef = {%.4f, %.4f, %.4f};" "PARAM vcoef = {%.4f, %.4f, %.4f};" "PARAM offsets = {%.4f, %.4f, %.4f};" "PARAM gamma = {%.4f, %.4f, %.4f};" - "TEMP res, y, u, v;" - "TEX y, fragment.texcoord[0], texture[0], %s;" - "MAD res, y, ycoef, offsets;" - "TEX u, fragment.texcoord[1], texture[1], %s;" - "MAD res, u, ucoef, res;" - "TEX v, fragment.texcoord[2], texture[2], %s;" - "MAD_SAT res, v, vcoef, res;" + "TEMP res;" + "MAD res.rgb, yuv.rrrr, ycoef, offsets;" + "MAD res.rgb, yuv.gggg, ucoef, res;" + "MAD_SAT res.rgb, yuv.bbbb, vcoef, res;" "POW result.color.r, res.r, gamma.r;" "POW result.color.g, res.g, gamma.g;" "POW result.color.b, res.b, gamma.b;" "END"; static const char *yuv_lookup_prog_template = - "!!ARBfp1.0\n" - "OPTION ARB_precision_hint_fastest;" "PARAM ycoef = {%.4f, %.4f, %.4f, 0};" "PARAM ucoef = {%.4f, %.4f, %.4f, 0};" "PARAM vcoef = {%.4f, %.4f, %.4f, 0};" "PARAM offsets = {%.4f, %.4f, %.4f, 0.125};" - "PARAM gamma = {%.4f, %.4f, %.4f};" - "TEMP res, y, u, v;" - "TEX y, fragment.texcoord[0], texture[0], %s;" - "MAD res, y, ycoef, offsets;" - "TEX u, fragment.texcoord[1], texture[1], %s;" - "MAD res, u, ucoef, res;" - "TEX v, fragment.texcoord[2], texture[2], %s;" - "MAD res, v, vcoef, res;" - "TEX result.color.r, res.raaa, texture[3], 2D;" + "TEMP res;" + "MAD res, yuv.rrrr, ycoef, offsets;" + "MAD res.rgb, yuv.gggg, ucoef, res;" + "MAD res.rgb, yuv.bbbb, vcoef, res;" + "TEX result.color.r, res.raaa, texture[%c], 2D;" "ADD res.a, res.a, 0.25;" - "TEX result.color.g, res.gaaa, texture[3], 2D;" + "TEX result.color.g, res.gaaa, texture[%c], 2D;" "ADD res.a, res.a, 0.25;" - "TEX result.color.b, res.baaa, texture[3], 2D;" + "TEX result.color.b, res.baaa, texture[%c], 2D;" "END"; +static void create_scaler_textures(int scaler, int *texu, char *texs) { + switch (scaler) { + case YUV_SCALER_BILIN: + break; + default: + mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler); + } +} + +static void gen_gamma_map(unsigned char *map, int size, float gamma); + +//! resolution of texture for gamma lookup table +#define LOOKUP_RES 512 +static void create_conv_textures(int conv, int *texu, char *texs, + int brightness, int contrast, int uvcos, int uvsin, + int rgamma, int ggamma, int bgamma) { + unsigned char *lookup_data = NULL; + switch (conv) { + case YUV_CONVERSION_FRAGMENT: + case YUV_CONVERSION_FRAGMENT_POW: + break; + case YUV_CONVERSION_FRAGMENT_LOOKUP: + texs[0] = (*texu)++; + ActiveTexture(GL_TEXTURE0 + texs[0]); + lookup_data = malloc(4 * LOOKUP_RES); + gen_gamma_map(lookup_data, LOOKUP_RES, rgamma); + gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, ggamma); + gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, bgamma); + glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LINEAR, + LOOKUP_RES, 4, 0); + glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data, + LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0); + ActiveTexture(GL_TEXTURE0); + texs[0] += '0'; + break; + default: + mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv); + } + if (lookup_data) + free(lookup_data); +} + +static void add_scaler(int scaler, char **prog_pos, int *remain, char *texs, + char in_tex, char out_comp, int rect, int texw, int texh) { + switch (scaler) { + case YUV_SCALER_BILIN: + snprintf(*prog_pos, *remain, bilin_filt_template, out_comp, in_tex, + in_tex, rect ? "RECT" : "2D"); + break; + } + *remain -= strlen(*prog_pos); + *prog_pos += strlen(*prog_pos); +} + /** * \brief setup a fragment program that will do YUV->RGB conversion * \param brightness brightness adjustment offset @@ -677,37 +717,48 @@ static const char *yuv_lookup_prog_template = */ static void glSetupYUVFragprog(float brightness, float contrast, float uvcos, float uvsin, float rgamma, - float ggamma, float bgamma, int type, int rect) { - char yuv_prog[1000]; - const char *prog_template = yuv_prog_template; - char *tex_type = rect ? "RECT" : "2D"; - int lookup = 0; + float ggamma, float bgamma, int type, int rect, + int texw, int texh) { + char yuv_prog[4000] = + "!!ARBfp1.0\n" + "OPTION ARB_precision_hint_fastest;" + // all scaler variables must go here so they aren't defined + // multiple times when the same scaler is used more than once + "TEMP yuv;"; + int prog_remain = sizeof(yuv_prog) - strlen(yuv_prog); + char *prog_pos = &yuv_prog[strlen(yuv_prog)]; + int cur_texu = 3; + char lum_scale_texs[1]; + char chrom_scale_texs[1]; + char conv_texs[1]; GLint i; // this is the conversion matrix, with y, u, v factors // for red, green, blue and the constant offsets float ry, ru, rv, rc; float gy, gu, gv, gc; float by, bu, bv, bc; - switch (type) { - case YUV_CONVERSION_FRAGMENT_POW: - prog_template = yuv_pow_prog_template; - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP: - prog_template = yuv_lookup_prog_template; - lookup = 1; - break; - } - glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i); - if (i < 3) - mp_msg(MSGT_VO, MSGL_ERR, - "[gl] 3 texture units needed for YUV fragment support (found %i)\n", i); - if (lookup && i < 4) + create_scaler_textures(YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs); + if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type)) + memcpy(chrom_scale_texs, lum_scale_texs, sizeof(chrom_scale_texs)); + else + create_scaler_textures(YUV_CHROM_SCALER(type), &cur_texu, chrom_scale_texs); + create_conv_textures(YUV_CONVERSION(type), &cur_texu, conv_texs, + brightness, contrast, uvcos, uvsin, rgamma, ggamma, bgamma); + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &i); + if (i < cur_texu) mp_msg(MSGT_VO, MSGL_ERR, - "[gl] 4 texture units needed for YUV fragment support with lookup (found %i)\n", i); + "[gl] %i texture units needed for this type of YUV fragment support (found %i)\n", + cur_texu, i); if (!ProgramString) { mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n"); return; } + add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs, + '0', 'r', rect, texw, texh); + add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, + '1', 'g', rect, texw / 2, texh / 2); + add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, + '2', 'b', rect, texw / 2, texh / 2); ry = 1.164 * contrast; gy = 1.164 * contrast; by = 1.164 * contrast; @@ -725,11 +776,26 @@ static void glSetupYUVFragprog(float brightness, float contrast, rc += 0.5 - contrast / 2.0; gc += 0.5 - contrast / 2.0; bc += 0.5 - contrast / 2.0; - rgamma = 1.0 / rgamma; - ggamma = 1.0 / ggamma; - bgamma = 1.0 / bgamma; - snprintf(yuv_prog, 1000, prog_template, ry, gy, by, ru, gu, bu, rv, gv, bv, - rc, gc, bc, rgamma, bgamma, bgamma, tex_type, tex_type, tex_type); + switch (YUV_CONVERSION(type)) { + case YUV_CONVERSION_FRAGMENT: + snprintf(prog_pos, prog_remain, yuv_prog_template, + ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc); + break; + case YUV_CONVERSION_FRAGMENT_POW: + snprintf(prog_pos, prog_remain, yuv_pow_prog_template, + ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc, + (float)1.0 / rgamma, (float)1.0 / bgamma, (float)1.0 / bgamma); + break; + case YUV_CONVERSION_FRAGMENT_LOOKUP: + snprintf(prog_pos, prog_remain, yuv_lookup_prog_template, + ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc, + conv_texs[0], conv_texs[0], conv_texs[0]); + break; + default: + mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type)); + break; + } + mp_msg(MSGT_VO, MSGL_V, "[gl] generated fragment program:\n%s\n", yuv_prog); ProgramString(GL_FRAGMENT_PROGRAM, GL_PROGRAM_FORMAT_ASCII, strlen(yuv_prog), yuv_prog); glGetIntegerv(GL_PROGRAM_ERROR_POSITION, &i); @@ -757,9 +823,6 @@ static void gen_gamma_map(unsigned char *map, int size, float gamma) { } } -//! resolution of texture for gamma lookup table -#define LOOKUP_RES 512 - /** * \brief setup YUV->RGB conversion * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D) @@ -776,10 +839,11 @@ static void gen_gamma_map(unsigned char *map, int size, float gamma) { void glSetupYUVConversion(GLenum target, int type, float brightness, float contrast, float hue, float saturation, - float rgamma, float ggamma, float bgamma) { + float rgamma, float ggamma, float bgamma, + int texw, int texh) { float uvcos = saturation * cos(hue); float uvsin = saturation * sin(hue); - switch (type) { + switch (YUV_CONVERSION(type)) { case YUV_CONVERSION_COMBINERS: glSetupYUVCombiners(uvcos, uvsin); break; @@ -787,24 +851,15 @@ void glSetupYUVConversion(GLenum target, int type, glSetupYUVCombinersATI(uvcos, uvsin); break; case YUV_CONVERSION_FRAGMENT_LOOKUP: - { - unsigned char lookup_data[4 * LOOKUP_RES]; - gen_gamma_map(lookup_data, LOOKUP_RES, rgamma); - gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, ggamma); - gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, bgamma); - ActiveTexture(GL_TEXTURE3); - glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LINEAR, - LOOKUP_RES, 4, 0); - glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data, - LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0); - ActiveTexture(GL_TEXTURE0); - } case YUV_CONVERSION_FRAGMENT: case YUV_CONVERSION_FRAGMENT_POW: glSetupYUVFragprog(brightness, contrast, uvcos, uvsin, rgamma, ggamma, bgamma, type, - target == GL_TEXTURE_RECTANGLE); + target == GL_TEXTURE_RECTANGLE, + texw, texh); break; + default: + mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type)); } } @@ -816,7 +871,7 @@ void glSetupYUVConversion(GLenum target, int type, */ void glEnableYUVConversion(GLenum target, int type) { if (type <= 0) return; - switch (type) { + switch (YUV_CONVERSION(type)) { case YUV_CONVERSION_COMBINERS: ActiveTexture(GL_TEXTURE1); glEnable(target); @@ -849,7 +904,7 @@ void glEnableYUVConversion(GLenum target, int type) { */ void glDisableYUVConversion(GLenum target, int type) { if (type <= 0) return; - switch (type) { + switch (YUV_CONVERSION(type)) { case YUV_CONVERSION_COMBINERS: ActiveTexture(GL_TEXTURE1); glDisable(target); diff --git a/libvo/gl_common.h b/libvo/gl_common.h index cf08f988ad..d9b9193c98 100644 --- a/libvo/gl_common.h +++ b/libvo/gl_common.h @@ -223,11 +223,28 @@ void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h, #define YUV_CONVERSION_FRAGMENT_LOOKUP 4 //! use ATI specific register combiners ("fragment program") #define YUV_CONVERSION_COMBINERS_ATI 5 +//! use normal bilinear scaling for textures +#define YUV_SCALER_BILIN 0 +//! mask for conversion type +#define YUV_CONVERSION_MASK 0xF +//! mask for scaler type +#define YUV_SCALER_MASK 0xF +//! shift value for luminance scaler type +#define YUV_LUM_SCALER_SHIFT 8 +//! shift value for chrominance scaler type +#define YUV_CHROM_SCALER_SHIFT 12 +//! extract conversion out of type +#define YUV_CONVERSION(t) (t & YUV_CONVERSION_MASK) +//! extract luminance scaler out of type +#define YUV_LUM_SCALER(t) ((t >> YUV_LUM_SCALER_SHIFT) & YUV_SCALER_MASK) +//! extract chrominance scaler out of type +#define YUV_CHROM_SCALER(t) ((t >> YUV_CHROM_SCALER_SHIFT) & YUV_SCALER_MASK) /** \} */ void glSetupYUVConversion(GLenum target, int type, float brightness, float contrast, float hue, float saturation, - float rgamma, float ggamma, float bgamma); + float rgamma, float ggamma, float bgamma, + int texw, int texh); void glEnableYUVConversion(GLenum target, int type); void glDisableYUVConversion(GLenum target, int type); diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index bcb65737b0..6385a74d96 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -59,6 +59,9 @@ static int osd_color; static int use_aspect; static int use_yuv; +static int lscale; +static int cscale; +static int yuvconvtype; static int use_rectangle; static int err_shown; static uint32_t image_width; @@ -156,8 +159,9 @@ static void update_yuvconv(void) { float rgamma = exp(log(8.0) * eq_rgamma / 100.0); float ggamma = exp(log(8.0) * eq_ggamma / 100.0); float bgamma = exp(log(8.0) * eq_bgamma / 100.0); - glSetupYUVConversion(gl_target, use_yuv, bri, cont, hue, sat, - rgamma, ggamma, bgamma); + glSetupYUVConversion(gl_target, yuvconvtype, bri, cont, hue, sat, + rgamma, ggamma, bgamma, + texture_width, texture_height); if (custom_prog) { FILE *f = fopen(custom_prog, "r"); if (!f) @@ -511,13 +515,13 @@ flip_page(void) glColor3f(1,1,1); if (image_format == IMGFMT_YV12) - glEnableYUVConversion(gl_target, use_yuv); + glEnableYUVConversion(gl_target, yuvconvtype); glDrawTex(0, 0, image_width, image_height, 0, 0, image_width, image_height, texture_width, texture_height, use_rectangle == 1, image_format == IMGFMT_YV12, mpi_flipped); if (image_format == IMGFMT_YV12) - glDisableYUVConversion(gl_target, use_yuv); + glDisableYUVConversion(gl_target, yuvconvtype); if (osdtexCnt > 0) { // set special rendering parameters @@ -685,6 +689,8 @@ static opt_t subopts[] = { {"slice-height", OPT_ARG_INT, &slice_height, (opt_test_f)int_non_neg}, {"rectangle", OPT_ARG_INT, &use_rectangle,(opt_test_f)int_non_neg}, {"yuv", OPT_ARG_INT, &use_yuv, (opt_test_f)int_non_neg}, + {"lscale", OPT_ARG_INT, &lscale, (opt_test_f)int_non_neg}, + {"cscale", OPT_ARG_INT, &cscale, (opt_test_f)int_non_neg}, {"glfinish", OPT_ARG_BOOL, &use_glFinish, NULL}, {"swapinterval", OPT_ARG_INT, &swap_interval,NULL}, {"customprog", OPT_ARG_MSTRZ,&custom_prog, NULL}, @@ -702,6 +708,8 @@ static int preinit(const char *arg) scaled_osd = 0; use_aspect = 1; use_yuv = 0; + lscale = 0; + cscale = 0; use_rectangle = 0; use_glFinish = 0; swap_interval = 1; @@ -757,6 +765,7 @@ static int preinit(const char *arg) gl_target = GL_TEXTURE_2D; if (slice_height == -1) slice_height = use_yuv ? 16 : 4; + yuvconvtype = use_yuv | lscale << YUV_LUM_SCALER_SHIFT | cscale << YUV_CHROM_SCALER_SHIFT; if (many_fmts) mp_msg (MSGT_VO, MSGL_INFO, "[gl] using extended formats. " "Use -vo gl:nomanyfmts if playback fails.\n"); diff --git a/libvo/vo_gl2.c b/libvo/vo_gl2.c index 036f3f4fdb..8dd0a297d7 100644 --- a/libvo/vo_gl2.c +++ b/libvo/vo_gl2.c @@ -773,7 +773,8 @@ static int initGl(uint32_t d_width, uint32_t d_height) BindProgram(GL_FRAGMENT_PROGRAM, fragprog); break; } - glSetupYUVConversion(GL_TEXTURE_2D, use_yuv, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0); + glSetupYUVConversion(GL_TEXTURE_2D, use_yuv, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, + texture_width, texture_height); } gl_set_antialias(0); -- cgit v1.2.3