From 8e35068138e7e6398c03b6b38a69be9aaef426c7 Mon Sep 17 00:00:00 2001 From: reimar Date: Wed, 30 Dec 2009 11:32:24 +0000 Subject: Support all planar YUV formats in OpenGL vos. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@30139 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libvo/gl_common.c | 17 ++++++++++--- libvo/gl_common.h | 2 ++ libvo/vo_gl.c | 76 ++++++++++++++++++++++++++++++++++--------------------- libvo/vo_gl2.c | 60 +++++++++++++++++++++++++------------------ 4 files changed, 97 insertions(+), 58 deletions(-) diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 47bc727565..9bce6634f0 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -234,6 +234,10 @@ int glFindFormat(uint32_t fmt, int *bpp, GLint *gl_texfmt, if (!gl_format) gl_format = &dummy2; if (!gl_type) gl_type = &dummy2; + // these are all the same for our purpose + if (mp_get_chroma_shift(fmt, NULL, NULL)) + fmt = IMGFMT_YV12; + *bpp = IMGFMT_IS_BGR(fmt)?IMGFMT_BGR_DEPTH(fmt):IMGFMT_RGB_DEPTH(fmt); *gl_texfmt = 3; switch (fmt) { @@ -1323,9 +1327,9 @@ static void glSetupYUVFragprog(gl_conversion_params_t *params) { add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs, '0', 'r', rect, texw, texh, params->filter_strength); add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, - '1', 'g', rect, texw / 2, texh / 2, params->filter_strength); + '1', 'g', rect, params->chrom_texw, params->chrom_texh, params->filter_strength); add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, - '2', 'b', rect, texw / 2, texh / 2, params->filter_strength); + '2', 'b', rect, params->chrom_texw, params->chrom_texh, params->filter_strength); get_yuv2rgb_coeffs(params, yuv2rgb); switch (YUV_CONVERSION(type)) { case YUV_CONVERSION_FRAGMENT: @@ -1496,14 +1500,19 @@ void glDisableYUVConversion(GLenum target, int type) { * \param sx width of texture in pixels * \param sy height of texture in pixels * \param rect_tex whether this texture uses texture_rectangle extension - * \param is_yv12 if set, also draw the textures from units 1 and 2 + * \param is_yv12 if != 0, also draw the textures from units 1 and 2, + * bits 8 - 15 and 16 - 23 specify the x and y scaling of those textures * \param flip flip the texture upside down * \ingroup gltexture */ void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, int sx, int sy, int rect_tex, int is_yv12, int flip) { - GLfloat tx2 = tx / 2, ty2 = ty / 2, tw2 = tw / 2, th2 = th / 2; + int chroma_x_shift = (is_yv12 >> 8) & 31; + int chroma_y_shift = (is_yv12 >> 16) & 31; + GLfloat xscale = 1 << chroma_x_shift; + GLfloat yscale = 1 << chroma_y_shift; + GLfloat tx2 = tx / xscale, ty2 = ty / yscale, tw2 = tw / xscale, th2 = th / yscale; if (!rect_tex) { tx /= sx; ty /= sy; tw /= sx; th /= sy; tx2 = tx, ty2 = ty, tw2 = tw, th2 = th; diff --git a/libvo/gl_common.h b/libvo/gl_common.h index 58c4b0dcef..23a78c24a0 100644 --- a/libvo/gl_common.h +++ b/libvo/gl_common.h @@ -339,6 +339,8 @@ typedef struct { float bgamma; int texw; int texh; + int chrom_texw; + int chrom_texh; float filter_strength; } gl_conversion_params_t; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 5ea2c3c726..058cfb614f 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -93,6 +93,7 @@ static int use_ycbcr; #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS) | (1 << YUV_CONVERSION_COMBINERS_ATI))) #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT)) static int use_yuv; +static int is_yuv; static int lscale; static int cscale; static float filter_strength; @@ -206,6 +207,7 @@ static void texSize(int w, int h, int *texw, int *texh) { //! maximum size of custom fragment program #define MAX_CUSTOM_PROG_SIZE (1024 * 1024) static void update_yuvconv(void) { + int xs, ys; float bri = eq_bri / 100.0; float cont = (eq_cont + 100) / 100.0; float hue = eq_hue / 100.0 * 3.1415927; @@ -215,7 +217,10 @@ static void update_yuvconv(void) { float bgamma = exp(log(8.0) * eq_bgamma / 100.0); gl_conversion_params_t params = {gl_target, yuvconvtype, bri, cont, hue, sat, rgamma, ggamma, bgamma, - texture_width, texture_height, filter_strength}; + texture_width, texture_height, 0, 0, filter_strength}; + mp_get_chroma_shift(image_format, &xs, &ys); + params.chrom_texw = params.texw >> xs; + params.chrom_texh = params.texh >> ys; glSetupYUVConversion(¶ms); if (custom_prog) { FILE *f = fopen(custom_prog, "r"); @@ -478,8 +483,10 @@ static int initGl(uint32_t d_width, uint32_t d_height) { mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n", texture_width, texture_height); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { int i; + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); GenTextures(21, default_texs); default_texs[21] = 0; for (i = 0; i < 7; i++) { @@ -490,18 +497,18 @@ static int initGl(uint32_t d_width, uint32_t d_height) { } ActiveTexture(GL_TEXTURE1); glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); if (mipmap_gen) TexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE); ActiveTexture(GL_TEXTURE2); glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); if (mipmap_gen) TexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE); ActiveTexture(GL_TEXTURE0); BindTexture(gl_target, 0); } - if (image_format == IMGFMT_YV12 || custom_prog) + if (is_yuv || custom_prog) { if ((MASK_NOT_COMBINERS & (1 << use_yuv)) || custom_prog) { if (!GenPrograms || !BindProgram) { @@ -533,9 +540,12 @@ static int initGl(uint32_t d_width, uint32_t d_height) { static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { + int xs, ys; image_height = height; image_width = width; image_format = format; + is_yuv = mp_get_chroma_shift(image_format, &xs, &ys) > 0; + is_yuv |= (xs << 8) | (ys << 16); glFindFormat(format, NULL, &gl_texfmt, &gl_format, &gl_type); int_pause = 0; @@ -712,14 +722,14 @@ static void do_render(void) { // BindTexture(GL_TEXTURE_2D, texture_id); Color3f(1,1,1); - if (image_format == IMGFMT_YV12 || custom_prog) + if (is_yuv || custom_prog) 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, + use_rectangle == 1, is_yuv, mpi_flipped ^ vo_flipped); - if (image_format == IMGFMT_YV12 || custom_prog) + if (is_yuv || custom_prog) glDisableYUVConversion(gl_target, yuvconvtype); } @@ -748,13 +758,15 @@ static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) mpi_flipped = stride[0] < 0; glUploadTex(gl_target, gl_format, gl_type, src[0], stride[0], x, y, w, h, slice_height); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); ActiveTexture(GL_TEXTURE1); glUploadTex(gl_target, gl_format, gl_type, src[1], stride[1], - x / 2, y / 2, w / 2, h / 2, slice_height); + x >> xs, y >> ys, w >> xs, h >> ys, slice_height); ActiveTexture(GL_TEXTURE2); glUploadTex(gl_target, gl_format, gl_type, src[2], stride[2], - x / 2, y / 2, w / 2, h / 2, slice_height); + x >> xs, y >> ys, w >> xs, h >> ys, slice_height); ActiveTexture(GL_TEXTURE0); } return 0; @@ -812,14 +824,16 @@ static uint32_t get_image(mp_image_t *mpi) { err_shown = 1; return VO_FALSE; } - if (mpi->imgfmt == IMGFMT_YV12) { - // YV12 + if (is_yuv) { + // planar YUV + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); mpi->flags |= MP_IMGFLAG_COMMON_STRIDE | MP_IMGFLAG_COMMON_PLANE; mpi->stride[0] = mpi->width; mpi->planes[1] = mpi->planes[0] + mpi->stride[0] * mpi->height; - mpi->stride[1] = mpi->width >> 1; - mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> 1); - mpi->stride[2] = mpi->width >> 1; + mpi->stride[1] = mpi->width >> xs; + mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> ys); + mpi->stride[2] = mpi->width >> xs; if (ati_hack && !mesa_buffer) { mpi->flags &= ~MP_IMGFLAG_COMMON_PLANE; if (!gl_buffer_uv[0]) GenBuffers(2, gl_buffer_uv); @@ -869,17 +883,19 @@ static uint32_t draw_image(mp_image_t *mpi) { mpi2.flags = 0; mpi2.type = MP_IMGTYPE_TEMP; mpi2.width = mpi2.w; mpi2.height = mpi2.h; if (force_pbo && !(mpi->flags & MP_IMGFLAG_DIRECT) && !gl_bufferptr && get_image(&mpi2) == VO_TRUE) { - int bpp = mpi->imgfmt == IMGFMT_YV12 ? 8 : mpi->bpp; + int bpp = is_yuv ? 8 : mpi->bpp; + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); memcpy_pic(mpi2.planes[0], mpi->planes[0], mpi->w * bpp / 8, mpi->h, mpi2.stride[0], mpi->stride[0]); - if (mpi->imgfmt == IMGFMT_YV12) { - memcpy_pic(mpi2.planes[1], mpi->planes[1], mpi->w >> 1, mpi->h >> 1, mpi2.stride[1], mpi->stride[1]); - memcpy_pic(mpi2.planes[2], mpi->planes[2], mpi->w >> 1, mpi->h >> 1, mpi2.stride[2], mpi->stride[2]); + if (is_yuv) { + memcpy_pic(mpi2.planes[1], mpi->planes[1], mpi->w >> xs, mpi->h >> ys, mpi2.stride[1], mpi->stride[1]); + memcpy_pic(mpi2.planes[2], mpi->planes[2], mpi->w >> xs, mpi->h >> ys, mpi2.stride[2], mpi->stride[2]); } if (ati_hack) { // since we have to do a full upload we need to clear the borders clear_border(mpi2.planes[0], mpi->w * bpp / 8, mpi2.stride[0], mpi->h, mpi2.height, 0); - if (mpi->imgfmt == IMGFMT_YV12) { - clear_border(mpi2.planes[1], mpi->w >> 1, mpi2.stride[1], mpi->h >> 1, mpi2.height >> 1, 128); - clear_border(mpi2.planes[2], mpi->w >> 1, mpi2.stride[2], mpi->h >> 1, mpi2.height >> 1, 128); + if (is_yuv) { + clear_border(mpi2.planes[1], mpi->w >> xs, mpi2.stride[1], mpi->h >> ys, mpi2.height >> ys, 128); + clear_border(mpi2.planes[2], mpi->w >> xs, mpi2.stride[2], mpi->h >> ys, mpi2.height >> ys, 128); } } mpi = &mpi2; @@ -909,7 +925,9 @@ static uint32_t draw_image(mp_image_t *mpi) { } glUploadTex(gl_target, gl_format, gl_type, planes[0], stride[0], mpi->x, mpi->y, w, h, slice); - if (mpi->imgfmt == IMGFMT_YV12) { + if (is_yuv) { + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) { BindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_buffer_uv[0]); UnmapBuffer(GL_PIXEL_UNPACK_BUFFER); @@ -917,7 +935,7 @@ static uint32_t draw_image(mp_image_t *mpi) { } ActiveTexture(GL_TEXTURE1); glUploadTex(gl_target, gl_format, gl_type, planes[1], stride[1], - mpi->x / 2, mpi->y / 2, w / 2, h / 2, slice); + mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys, slice); if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) { BindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_buffer_uv[1]); UnmapBuffer(GL_PIXEL_UNPACK_BUFFER); @@ -925,7 +943,7 @@ static uint32_t draw_image(mp_image_t *mpi) { } ActiveTexture(GL_TEXTURE2); glUploadTex(gl_target, gl_format, gl_type, planes[2], stride[2], - mpi->x / 2, mpi->y / 2, w / 2, h / 2, slice); + mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys, slice); ActiveTexture(GL_TEXTURE0); } if (mpi->flags & MP_IMGFLAG_DIRECT) { @@ -953,7 +971,7 @@ query_format(uint32_t format) caps |= VFCAP_OSD | VFCAP_EOSD | (scaled_osd ? 0 : VFCAP_EOSD_UNSCALED); if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA) return caps; - if (use_yuv && format == IMGFMT_YV12) + if (use_yuv && mp_get_chroma_shift(format, NULL, NULL)) return caps; // HACK, otherwise we get only b&w with some filters (e.g. -vf eq) // ideally MPlayer should be fixed instead not to use Y800 when it has the choice @@ -1184,7 +1202,7 @@ static int control(uint32_t request, void *data, ...) resize(vo_dwidth, vo_dheight); return VO_TRUE; case VOCTRL_GET_EQUALIZER: - if (image_format == IMGFMT_YV12) { + if (is_yuv) { int i; va_list va; int *value; @@ -1200,7 +1218,7 @@ static int control(uint32_t request, void *data, ...) } break; case VOCTRL_SET_EQUALIZER: - if (image_format == IMGFMT_YV12) { + if (is_yuv) { int i; va_list va; int value; diff --git a/libvo/vo_gl2.c b/libvo/vo_gl2.c index 989b470f1a..fc28fe3a67 100644 --- a/libvo/vo_gl2.c +++ b/libvo/vo_gl2.c @@ -88,6 +88,7 @@ static int isGL12 = GL_FALSE; static int gl_bilinear=1; static int gl_antialias=0; static int use_yuv; +static int is_yuv; static int use_glFinish; static void (*draw_alpha_fnc) @@ -184,7 +185,7 @@ static int initTextures(void) s*=2; texture_height=s; - if (image_format != IMGFMT_YV12) + if (!is_yuv) gl_internal_format = getInternalFormat(); /* Test the max texture size */ @@ -263,7 +264,7 @@ static int initTextures(void) glGenTextures (1, &(tsq->texobj)); glBindTexture (GL_TEXTURE_2D, tsq->texobj); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { glGenTextures(2, tsq->uvtexobjs); ActiveTexture(GL_TEXTURE1); glBindTexture (GL_TEXTURE_2D, tsq->uvtexobjs[0]); @@ -276,13 +277,15 @@ static int initTextures(void) texture_width, texture_height, 0); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); ActiveTexture(GL_TEXTURE1); glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format, gl_bitmap_type, GL_LINEAR, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); ActiveTexture(GL_TEXTURE2); glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format, gl_bitmap_type, GL_LINEAR, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); ActiveTexture(GL_TEXTURE0); } @@ -381,7 +384,7 @@ static void drawTextureDisplay (void) glColor3f(1.0,1.0,1.0); - if (image_format == IMGFMT_YV12) + if (is_yuv) glEnableYUVConversion(GL_TEXTURE_2D, use_yuv); for (y = 0; y < texnumy; y++) { int thish = texture_height; @@ -392,7 +395,7 @@ static void drawTextureDisplay (void) if (x == texnumx - 1 && image_width % texture_width) thisw = image_width % texture_width; glBindTexture (GL_TEXTURE_2D, square->texobj); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { ActiveTexture(GL_TEXTURE1); glBindTexture (GL_TEXTURE_2D, square->uvtexobjs[0]); ActiveTexture(GL_TEXTURE2); @@ -409,11 +412,11 @@ static void drawTextureDisplay (void) glDrawTex(square->fx, square->fy, square->fw, square->fh, 0, 0, texture_width, texture_height, texture_width, texture_height, - 0, image_format == IMGFMT_YV12, 0); + 0, is_yuv, 0); square++; } /* for all texnumx */ } /* for all texnumy */ - if (image_format == IMGFMT_YV12) + if (is_yuv) glDisableYUVConversion(GL_TEXTURE_2D, use_yuv); texdirty = 0; } @@ -565,10 +568,11 @@ static int initGl(uint32_t d_width, uint32_t d_height) glDepthMask(GL_FALSE); glDisable(GL_CULL_FACE); glEnable (GL_TEXTURE_2D); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { + int xs, ys; gl_conversion_params_t params = {GL_TEXTURE_2D, use_yuv, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, - texture_width, texture_height}; + texture_width, texture_height, 0, 0, 0}; switch (use_yuv) { case YUV_CONVERSION_FRAGMENT_LOOKUP: glGenTextures(1, &lookupTex); @@ -586,6 +590,9 @@ static int initGl(uint32_t d_width, uint32_t d_height) BindProgram(GL_FRAGMENT_PROGRAM, fragprog); break; } + mp_get_chroma_shift(image_format, &xs, &ys); + params.chrom_texw = params.texw >> xs; + params.chrom_texh = params.texh >> ys; glSetupYUVConversion(¶ms); } @@ -613,11 +620,14 @@ static int initGl(uint32_t d_width, uint32_t d_height) static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { + int xs, ys; const unsigned char * glVersion; image_height = height; image_width = width; image_format = format; + is_yuv = mp_get_chroma_shift(image_format, &xs, &ys) > 0; + is_yuv |= (xs << 8) | (ys << 16); int_pause = 0; @@ -750,6 +760,8 @@ static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) int rem_h = h; struct TexSquare *texline = &texgrid[y / texture_height * texnumx]; int subtex_y = y % texture_width; + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); while (rem_h > 0) { int rem_w = w; struct TexSquare *tsq = &texline[x / texture_width]; @@ -769,24 +781,24 @@ static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) ActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tsq->uvtexobjs[0]); glUploadTex(GL_TEXTURE_2D, gl_bitmap_format, gl_bitmap_type, - uptr, ustride, subtex_x / 2, subtex_y / 2, - subtex_w / 2, subtex_h / 2, 0); + uptr, ustride, subtex_x >> xs, subtex_y >> ys, + subtex_w >> xs, subtex_h >> ys, 0); ActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, tsq->uvtexobjs[1]); glUploadTex(GL_TEXTURE_2D, gl_bitmap_format, gl_bitmap_type, - vptr, vstride, subtex_x / 2, subtex_y / 2, - subtex_w / 2, subtex_h / 2, 0); + vptr, vstride, subtex_x >> xs, subtex_y >> ys, + subtex_w >> xs, subtex_h >> ys, 0); subtex_x = 0; yptr += subtex_w; - uptr += subtex_w / 2; - vptr += subtex_w / 2; + uptr += subtex_w >> xs; + vptr += subtex_w >> xs; tsq++; rem_w -= subtex_w; } subtex_y = 0; yptr += subtex_h * ystride - w; - uptr += subtex_h / 2 * ustride - w / 2; - vptr += subtex_h / 2 * vstride - w / 2; + uptr += (subtex_h >> ys) * ustride - (w >> xs); + vptr += (subtex_h >> ys) * vstride - (w >> xs); texline += texnumx; rem_h -= subtex_h; } @@ -797,7 +809,7 @@ static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) static int draw_frame(uint8_t *src[]) { - if (image_format == IMGFMT_YV12) { + if (is_yuv) { mp_msg(MSGT_VO, MSGL_ERR, "[gl2] error: draw_frame called for YV12!\n"); return 0; } @@ -810,12 +822,10 @@ draw_frame(uint8_t *src[]) static int query_format(uint32_t format) { + if (use_yuv && mp_get_chroma_shift(format, NULL, NULL)) + return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | + VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE; switch(format) { - case IMGFMT_YV12: - if (use_yuv) - return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | - VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE; - break; #ifdef __APPLE__ case IMGFMT_RGB32: #else -- cgit v1.2.3