# HG changeset patch # User reimar # Date 1149689252 0 # Node ID dd9a6e8005f3550a9e2e6c173bd3de8eb9bb400f # Parent 0001a9a9f1a9c01057bbce88ea0a0972de44a61e Add bicubic texture scaling diff -r 0001a9a9f1a9 -r dd9a6e8005f3 DOCS/man/en/mplayer.1 --- a/DOCS/man/en/mplayer.1 Wed Jun 07 13:39:06 2006 +0000 +++ b/DOCS/man/en/mplayer.1 Wed Jun 07 14:07:32 2006 +0000 @@ -3077,6 +3077,16 @@ Provides saturation and hue control. This method is fast but inexact. .RE +.IPs [l|c]scaler= +Select the scaling function to use (seperately for luma and chroma). +Only valid for yuv modes 2, 3 and 4. +.RSss +0: Use simple linear filtering (default) +.br +1: Use bicubic filtering (better quality). +Older cards will not be able to handle this for chroma at least in fullscreen mode. +Also needs one additional texture unit. +.RE .IPs customprog= Load a custom fragment program from . See TOOLS/edgedect.fp for an example. diff -r 0001a9a9f1a9 -r dd9a6e8005f3 libvo/gl_common.c --- a/libvo/gl_common.c Wed Jun 07 13:39:06 2006 +0000 +++ b/libvo/gl_common.c Wed Jun 07 14:07:32 2006 +0000 @@ -607,9 +607,78 @@ EndFragmentShader(); } +static void store_weights(float x, GLfloat *dst) { + float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6; + float w1 = ((( 3 * x - 6) * x + 0) * x + 4) / 6; + float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6; + float w3 = ((( 1 * x + 0) * x + 0) * x + 0) / 6; + *dst++ = 1 + x - w1 / (w0 + w1); + *dst++ = 1 - x + w3 / (w2 + w3); + *dst++ = w0 + w1; + *dst++ = 0; +} + +//! to avoid artefacts this should be rather large +#define LOOKUP_BSPLINE_RES (1024) +/** + * \brief creates the 1D lookup texture needed for fast higher-order filtering + * \param unit texture unit to attach texture to + */ +static void gen_spline_lookup_tex(GLenum unit) { + GLfloat tex[4 * (LOOKUP_BSPLINE_RES + 2)]; + GLfloat *tp = &tex[4]; + int i; + for (i = 0; i < LOOKUP_BSPLINE_RES; i++) { + float x = (float)(i + 0.5) / LOOKUP_BSPLINE_RES; + store_weights(x, tp); + tp += 4; + } + store_weights(0, tex); + store_weights(1, &tex[4 * (LOOKUP_BSPLINE_RES + 1)]); + ActiveTexture(unit); + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA16, LOOKUP_BSPLINE_RES + 2, 1, GL_RGBA, GL_FLOAT, tex); + glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_PRIORITY, 1.0); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); + ActiveTexture(GL_TEXTURE0); +} + static const char *bilin_filt_template = "TEX yuv.%c, fragment.texcoord[%c], texture[%c], %s;"; +#define BICUB_FILT_MAIN(textype) \ + /* first y-interpolation */ \ + "SUB coord.xy, fragment.texcoord[%c], parmx.rara;" \ + "SUB coord.zw, coord.xyxy, parmy.arar;" \ + "TEX a.r, coord.zwzw, texture[%c], "textype";" \ + "ADD coord.zw, coord.xyxy, parmy.agag;" \ + "TEX a.g, coord.zwzw, texture[%c], "textype";" \ + "LRP a.b, parmy.b, a.rrrr, a.gggg;" \ + /* second y-interpolation */ \ + "ADD coord.xy, fragment.texcoord[%c], parmx.gaga;" \ + "SUB coord.zw, coord.xyxy, parmy.arar;" \ + "TEX a.r, coord.zwzw, texture[%c], "textype";" \ + "ADD coord.zw, coord.xyxy, parmy.agag;" \ + "TEX a.g, coord.zwzw, texture[%c], "textype";" \ + "LRP a.a, parmy.b, a.rrrr, a.gggg;" \ + /* x-interpolation */ \ + "LRP yuv.%c, parmx.b, a.bbbb, a.aaaa;" + +static const char *bicub_filt_template_2D = + "MAD coord.xy, fragment.texcoord[%c], {%f, %f}, {0.5, 0.5};" + "TEX parmx, coord.x, texture[%c], 1D;" + "MUL parmx.rg, parmx, {%f, %f};" + "TEX parmy, coord.y, texture[%c], 1D;" + "MUL parmy.rg, parmy, {%f, %f};" + BICUB_FILT_MAIN("2D"); + +static const char *bicub_filt_template_RECT = + "ADD coord, fragment.texcoord[%c], {0.5, 0.5};" + "TEX parmx, coord.x, texture[%c], 1D;" + "TEX parmy, coord.y, texture[%c], 1D;" + BICUB_FILT_MAIN("RECT"); + static const char *yuv_prog_template = "PARAM ycoef = {%.4f, %.4f, %.4f};" "PARAM ucoef = {%.4f, %.4f, %.4f};" @@ -656,6 +725,11 @@ switch (scaler) { case YUV_SCALER_BILIN: break; + case YUV_SCALER_BICUB: + texs[0] = (*texu)++; + gen_spline_lookup_tex(GL_TEXTURE0 + texs[0]); + texs[0] += '0'; + break; default: mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler); } @@ -701,6 +775,18 @@ snprintf(*prog_pos, *remain, bilin_filt_template, out_comp, in_tex, in_tex, rect ? "RECT" : "2D"); break; + case YUV_SCALER_BICUB: + if (rect) + snprintf(*prog_pos, *remain, bicub_filt_template_RECT, + in_tex, texs[0], texs[0], + in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp); + else + snprintf(*prog_pos, *remain, bicub_filt_template_2D, + in_tex, (float)texw, (float)texh, + texs[0], (float)1.0 / texw, (float)1.0 / texw, + texs[0], (float)1.0 / texh, (float)1.0 / texh, + in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp); + break; } *remain -= strlen(*prog_pos); *prog_pos += strlen(*prog_pos); @@ -724,7 +810,7 @@ "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;"; + "TEMP coord, parmx, parmy, a, yuv;"; int prog_remain = sizeof(yuv_prog) - strlen(yuv_prog); char *prog_pos = &yuv_prog[strlen(yuv_prog)]; int cur_texu = 3; diff -r 0001a9a9f1a9 -r dd9a6e8005f3 libvo/gl_common.h --- a/libvo/gl_common.h Wed Jun 07 13:39:06 2006 +0000 +++ b/libvo/gl_common.h Wed Jun 07 14:07:32 2006 +0000 @@ -225,6 +225,8 @@ #define YUV_CONVERSION_COMBINERS_ATI 5 //! use normal bilinear scaling for textures #define YUV_SCALER_BILIN 0 +//! use higher quality bicubic scaling for textures +#define YUV_SCALER_BICUB 1 //! mask for conversion type #define YUV_CONVERSION_MASK 0xF //! mask for scaler type