From dc582f2505d7583f414dcfa777371f986de381d3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 1 Dec 2013 23:39:13 +0100 Subject: vo_opengl: add support for rectangle textures This allows vo_opengl to use GL_TEXTURE_RECTANGLE textures, either by enabling it with the 'rectangle-textures' sub-option, or by having a hwdec backend force it. By default it's off. The _only_ reason we're adding this is because VDA can export rectangle textures only. --- video/out/gl_common.h | 3 ++ video/out/gl_video.c | 91 +++++++++++++++++++++++++++-------------- video/out/gl_video.h | 1 + video/out/gl_video_shaders.glsl | 34 +++++++++------ video/out/vo_opengl.c | 1 + 5 files changed, 86 insertions(+), 44 deletions(-) (limited to 'video') diff --git a/video/out/gl_common.h b/video/out/gl_common.h index 8b5ac63d9a..c19ec7f73d 100644 --- a/video/out/gl_common.h +++ b/video/out/gl_common.h @@ -177,6 +177,9 @@ struct gl_hwdec { // internal representation in gl_video.c as the hardware texture. // It's used to build the rendering chain, and also as screenshot format. int converted_imgfmt; + // Normally this is GL_TEXTURE_2D, but the hwdec driver can set it to + // GL_TEXTURE_RECTANGLE. + GLenum gl_texture_target; }; struct gl_hwdec_driver { diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 881f649a34..4c901965fa 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -145,6 +145,8 @@ struct gl_video { int depth_g; + GLenum gl_target; // texture target (GL_TEXTURE_2D, ...) for video and FBOs + GLuint vertex_buffer; GLuint vao; @@ -340,6 +342,7 @@ const struct m_sub_options gl_video_conf = { ({"no", 0}, {"yes", 1}, {"", 1}, {"blend", 2})), + OPT_FLAG("rectangle-textures", use_rectangle, 0), {0} }, .size = sizeof(struct gl_video_opts), @@ -419,17 +422,19 @@ static void write_quad(struct vertex *va, float x0, float y0, float x1, float y1, float tx0, float ty0, float tx1, float ty1, float texture_w, float texture_h, - const uint8_t color[4], bool flip) + const uint8_t color[4], GLenum target, bool flip) { static const uint8_t white[4] = { 255, 255, 255, 255 }; if (!color) color = white; - tx0 /= texture_w; - ty0 /= texture_h; - tx1 /= texture_w; - ty1 /= texture_h; + if (target == GL_TEXTURE_2D) { + tx0 /= texture_w; + ty0 /= texture_h; + tx1 /= texture_w; + ty1 /= texture_h; + } if (flip) { float tmp = ty0; @@ -470,14 +475,14 @@ static bool fbotex_init(struct gl_video *p, struct fbotex *fbo, int w, int h, gl->GenFramebuffers(1, &fbo->fbo); gl->GenTextures(1, &fbo->texture); - gl->BindTexture(GL_TEXTURE_2D, fbo->texture); - gl->TexImage2D(GL_TEXTURE_2D, 0, iformat, + gl->BindTexture(p->gl_target, fbo->texture); + gl->TexImage2D(p->gl_target, 0, iformat, fbo->tex_w, fbo->tex_h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); + default_tex_params(gl, p->gl_target, GL_LINEAR); gl->BindFramebuffer(GL_FRAMEBUFFER, fbo->fbo); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, fbo->texture, 0); + p->gl_target, fbo->texture, 0); if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { MP_ERR(p, "Error: framebuffer completeness check failed!\n"); @@ -567,8 +572,20 @@ static void update_uniforms(struct gl_video *p, GLuint program) snprintf(textures_size_n, sizeof(textures_size_n), "textures_size[%d]", n); gl->Uniform1i(gl->GetUniformLocation(program, textures_n), n); - gl->Uniform2f(gl->GetUniformLocation(program, textures_size_n), - p->image.planes[n].tex_w, p->image.planes[n].tex_h); + if (p->gl_target == GL_TEXTURE_2D) { + gl->Uniform2f(gl->GetUniformLocation(program, textures_size_n), + p->image.planes[n].tex_w, p->image.planes[n].tex_h); + } else { + // Makes the pixel size calculation code think they are 1x1 + gl->Uniform2f(gl->GetUniformLocation(program, textures_size_n), 1, 1); + } + } + + loc = gl->GetUniformLocation(program, "chroma_div"); + if (loc >= 0) { + int xs = p->image_desc.chroma_xs; + int ys = p->image_desc.chroma_ys; + gl->Uniform2f(loc, 1.0 / (1 << xs), 1.0 / (1 << ys)); } loc = gl->GetUniformLocation(program, "chroma_center_offset"); @@ -588,8 +605,9 @@ static void update_uniforms(struct gl_video *p, GLuint program) // move chroma center to luma center (in chroma coord. space) float o_x = ls_w < 1 ? ls_w * -cx / 2 : 0; float o_y = ls_h < 1 ? ls_h * -cy / 2 : 0; - gl->Uniform2f(loc, o_x / FFMAX(p->image.planes[1].w, 1), - o_y / FFMAX(p->image.planes[1].h, 1)); + int c = p->gl_target == GL_TEXTURE_2D ? 1 : 0; + gl->Uniform2f(loc, o_x / FFMAX(p->image.planes[1].w * c, 1), + o_y / FFMAX(p->image.planes[1].h * c, 1)); } gl->Uniform2f(gl->GetUniformLocation(program, "dither_size"), @@ -798,6 +816,13 @@ static void compile_shaders(struct gl_video *p) char *header = talloc_asprintf(tmp, "#version %d\n%s%s", gl->glsl_version, shader_prelude, PRELUDE_END); + if (p->gl_target == GL_TEXTURE_RECTANGLE) { + shader_def(&header, "VIDEO_SAMPLER", "sampler2DRect"); + shader_def_opt(&header, "USE_RECTANGLE", true); + } else { + shader_def(&header, "VIDEO_SAMPLER", "sampler2D"); + } + // Need to pass alpha through the whole chain. (Not needed for OSD shaders.) if (p->opts.alpha_mode == 1) shader_def_opt(&header, "USE_ALPHA", p->has_alpha); @@ -1218,7 +1243,7 @@ static void set_image_textures(struct gl_video *p, struct video_image *vimg, for (int n = 0; n < 4; n++) { gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, imgtex[n]); + gl->BindTexture(p->gl_target, imgtex[n]); } gl->ActiveTexture(GL_TEXTURE0); } @@ -1229,7 +1254,7 @@ static void unset_image_textures(struct gl_video *p) for (int n = 0; n < 4; n++) { gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, 0); + gl->BindTexture(p->gl_target, 0); } gl->ActiveTexture(GL_TEXTURE0); @@ -1241,10 +1266,14 @@ static void init_video(struct gl_video *p, const struct mp_image_params *params) { GL *gl = p->gl; - check_gl_features(p); - init_format(params->imgfmt, p); + p->gl_target = p->opts.use_rectangle ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D; + if (p->hwdec_active) + p->gl_target = p->hwdec->gl_texture_target; + + check_gl_features(p); + p->image_w = params->w; p->image_h = params->h; p->image_dw = params->d_w; @@ -1295,13 +1324,13 @@ static void init_video(struct gl_video *p, const struct mp_image_params *params) gl->ActiveTexture(GL_TEXTURE0 + n); gl->GenTextures(1, &plane->gl_texture); - gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); + gl->BindTexture(p->gl_target, plane->gl_texture); - gl->TexImage2D(GL_TEXTURE_2D, 0, plane->gl_internal_format, + gl->TexImage2D(p->gl_target, 0, plane->gl_internal_format, plane->tex_w, plane->tex_h, 0, plane->gl_format, plane->gl_type, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); + default_tex_params(gl, p->gl_target, GL_LINEAR); } MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", @@ -1377,7 +1406,7 @@ static void render_to_fbo(struct gl_video *p, struct fbotex *fbo, write_quad(vb, -1, -1, 1, 1, x, y, x + w, y + h, tex_w, tex_h, - NULL, false); + NULL, p->gl_target, false); draw_triangles(p, vb, VERTICES_PER_QUAD); gl->BindFramebuffer(GL_FRAMEBUFFER, 0); @@ -1394,7 +1423,7 @@ static void handle_pass(struct gl_video *p, struct fbotex *chain, if (!program) return; - gl->BindTexture(GL_TEXTURE_2D, chain->texture); + gl->BindTexture(p->gl_target, chain->texture); gl->UseProgram(program); render_to_fbo(p, fbo, chain->vp_x, chain->vp_y, chain->vp_w, chain->vp_h, @@ -1448,7 +1477,7 @@ void gl_video_render_frame(struct gl_video *p) handle_pass(p, &chain, &p->scale_sep_fbo, p->scale_sep_program); - gl->BindTexture(GL_TEXTURE_2D, chain.texture); + gl->BindTexture(p->gl_target, chain.texture); gl->UseProgram(p->final_program); struct mp_rect src = {p->src_rect.x0, chain.vp_y, @@ -1468,7 +1497,7 @@ void gl_video_render_frame(struct gl_video *p) src.x0 / 2, src.y0, src.x0 / 2 + w / 2, src.y1, src_texw, src_texh, - NULL, is_flipped); + NULL, p->gl_target, is_flipped); draw_triangles(p, vb, VERTICES_PER_QUAD); glEnable3DRight(gl, p->opts.stereo_mode); @@ -1479,7 +1508,7 @@ void gl_video_render_frame(struct gl_video *p) src.x0 / 2 + imgw / 2, src.y0, src.x0 / 2 + imgw / 2 + w / 2, src.y1, src_texw, src_texh, - NULL, is_flipped); + NULL, p->gl_target, is_flipped); draw_triangles(p, vb, VERTICES_PER_QUAD); glDisable3D(gl, p->opts.stereo_mode); @@ -1490,7 +1519,7 @@ void gl_video_render_frame(struct gl_video *p) src.x0, src.y0, src.x1, src.y1, src_texw, src_texh, - NULL, is_flipped); + NULL, p->gl_target, is_flipped); draw_triangles(p, vb, VERTICES_PER_QUAD); } @@ -1644,8 +1673,8 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) plane_ptr = NULL; // PBO offset 0 } gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); - glUploadTex(gl, GL_TEXTURE_2D, plane->gl_format, plane->gl_type, + gl->BindTexture(p->gl_target, plane->gl_texture); + glUploadTex(gl, p->gl_target, plane->gl_format, plane->gl_type, plane_ptr, mpi->stride[n], 0, 0, plane->w, plane->h, 0); } gl->ActiveTexture(GL_TEXTURE0); @@ -1674,7 +1703,7 @@ struct mp_image *gl_video_download_image(struct gl_video *p) for (int n = 0; n < p->plane_count; n++) { struct texplane *plane = &vimg->planes[n]; gl->ActiveTexture(GL_TEXTURE0 + n); - glDownloadTex(gl, GL_TEXTURE_2D, plane->gl_format, plane->gl_type, + glDownloadTex(gl, p->gl_target, plane->gl_format, plane->gl_type, image->planes[n], image->stride[n]); } mp_image_set_attributes(image, &p->image_params); @@ -1711,7 +1740,7 @@ static void draw_osd_cb(void *ctx, struct mpgl_osd_part *osd, write_quad(&va[osd->num_vertices], b->x, b->y, b->x + b->dw, b->y + b->dh, pos.x, pos.y, pos.x + b->w, pos.y + b->h, - osd->w, osd->h, color, false); + osd->w, osd->h, color, GL_TEXTURE_2D, false); osd->num_vertices += VERTICES_PER_QUAD; } } @@ -2084,8 +2113,8 @@ struct gl_video *gl_video_init(GL *gl, struct mp_log *log) .gl = gl, .log = log, .opts = gl_video_opts_def, + .gl_target = GL_TEXTURE_2D, .gl_debug = true, - .colorspace = MP_CSP_DETAILS_DEFAULTS, .scalers = { { .index = 0, .name = "bilinear" }, { .index = 1, .name = "bilinear" }, diff --git a/video/out/gl_video.h b/video/out/gl_video.h index 27da29461c..a4f864a9dd 100644 --- a/video/out/gl_video.h +++ b/video/out/gl_video.h @@ -46,6 +46,7 @@ struct gl_video_opts { int stereo_mode; int alpha_mode; int chroma_location; + int use_rectangle; }; extern const struct m_sub_options gl_video_conf; diff --git a/video/out/gl_video_shaders.glsl b/video/out/gl_video_shaders.glsl index b0df20b544..af966905a0 100644 --- a/video/out/gl_video_shaders.glsl +++ b/video/out/gl_video_shaders.glsl @@ -112,12 +112,13 @@ void main() { } #!section frag_video -uniform sampler2D texture0; -uniform sampler2D texture1; -uniform sampler2D texture2; -uniform sampler2D texture3; +uniform VIDEO_SAMPLER texture0; +uniform VIDEO_SAMPLER texture1; +uniform VIDEO_SAMPLER texture2; +uniform VIDEO_SAMPLER texture3; uniform vec2 textures_size[4]; uniform vec2 chroma_center_offset; +uniform vec2 chroma_div; uniform sampler1D lut_c_1d; uniform sampler1D lut_l_1d; uniform sampler2D lut_c_2d; @@ -140,7 +141,7 @@ DECLARE_FRAGPARMS #define CONV_NV12 1 #define CONV_PLANAR 2 -vec4 sample_bilinear(sampler2D tex, vec2 texsize, vec2 texcoord) { +vec4 sample_bilinear(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { return texture(tex, texcoord); } @@ -161,7 +162,7 @@ vec4 calcweights(float s) { return t; } -vec4 sample_bicubic_fast(sampler2D tex, vec2 texsize, vec2 texcoord) { +vec4 sample_bicubic_fast(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { vec2 pt = 1 / texsize; vec2 fcoord = fract(texcoord * texsize + vec2(0.5, 0.5)); vec4 parmx = calcweights(fcoord.x); @@ -222,7 +223,7 @@ float[16] weights16(sampler2D lookup, float f) { } #define CONVOLUTION_SEP_N(NAME, N) \ - vec4 NAME(sampler2D tex, vec2 texcoord, vec2 pt, float weights[N]) { \ + vec4 NAME(VIDEO_SAMPLER tex, vec2 texcoord, vec2 pt, float weights[N]) {\ vec4 res = vec4(0); \ for (int n = 0; n < N; n++) { \ res += weights[n] * texture(tex, texcoord + pt * n); \ @@ -240,7 +241,7 @@ CONVOLUTION_SEP_N(convolution_sep16, 16) // The dir parameter is (0, 1) or (1, 0), and we expect the shader compiler to // remove all the redundant multiplications and additions. #define SAMPLE_CONVOLUTION_SEP_N(NAME, N, SAMPLERT, CONV_FUNC, WEIGHTS_FUNC)\ - vec4 NAME(vec2 dir, SAMPLERT lookup, sampler2D tex, vec2 texsize, \ + vec4 NAME(vec2 dir, SAMPLERT lookup, VIDEO_SAMPLER tex, vec2 texsize, \ vec2 texcoord) { \ vec2 pt = (1 / texsize) * dir; \ float fcoord = dot(fract(texcoord * texsize - 0.5), dir); \ @@ -258,7 +259,7 @@ SAMPLE_CONVOLUTION_SEP_N(sample_convolution_sep16, 16, sampler2D, convolution_se #define CONVOLUTION_N(NAME, N) \ - vec4 NAME(sampler2D tex, vec2 texcoord, vec2 pt, float taps_x[N], \ + vec4 NAME(VIDEO_SAMPLER tex, vec2 texcoord, vec2 pt, float taps_x[N], \ float taps_y[N]) { \ vec4 res = vec4(0); \ for (int y = 0; y < N; y++) { \ @@ -278,7 +279,7 @@ CONVOLUTION_N(convolution12, 12) CONVOLUTION_N(convolution16, 16) #define SAMPLE_CONVOLUTION_N(NAME, N, SAMPLERT, CONV_FUNC, WEIGHTS_FUNC) \ - vec4 NAME(SAMPLERT lookup, sampler2D tex, vec2 texsize, vec2 texcoord) {\ + vec4 NAME(SAMPLERT lookup, VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) {\ vec2 pt = 1 / texsize; \ vec2 fcoord = fract(texcoord * texsize - 0.5); \ vec2 base = texcoord - fcoord * pt; \ @@ -296,7 +297,7 @@ SAMPLE_CONVOLUTION_N(sample_convolution16, 16, sampler2D, convolution16, weights // Unsharp masking -vec4 sample_sharpen3(sampler2D tex, vec2 texsize, vec2 texcoord) { +vec4 sample_sharpen3(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { vec2 pt = 1 / texsize; vec2 st = pt * 0.5; vec4 p = texture(tex, texcoord); @@ -307,7 +308,7 @@ vec4 sample_sharpen3(sampler2D tex, vec2 texsize, vec2 texcoord) { return p + (p - 0.25 * sum) * filter_param1; } -vec4 sample_sharpen5(sampler2D tex, vec2 texsize, vec2 texcoord) { +vec4 sample_sharpen5(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { vec2 pt = 1 / texsize; vec2 st1 = pt * 1.2; vec4 p = texture(tex, texcoord); @@ -325,7 +326,14 @@ vec4 sample_sharpen5(sampler2D tex, vec2 texsize, vec2 texcoord) { } void main() { - vec2 chr_texcoord = texcoord + chroma_center_offset; + vec2 chr_texcoord = texcoord; +#ifdef USE_RECTANGLE + chr_texcoord = chr_texcoord * chroma_div; +#else + // Texture coordinates are [0,1], and chroma plane coordinates are + // magically rescaled. +#endif + chr_texcoord = chr_texcoord + chroma_center_offset; #ifndef USE_CONV #define USE_CONV 0 #endif diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index e086e36e7d..774d87ed05 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -206,6 +206,7 @@ static void load_hwdec_driver(struct gl_priv *p, .log = mp_log_new(hwdec, p->vo->log, drv->api_name), .mpgl = p->glctx, .info = talloc_zero(hwdec, struct mp_hwdec_info), + .gl_texture_target = GL_TEXTURE_2D, }; mpgl_lock(p->glctx); if (hwdec->driver->create(hwdec) < 0) { -- cgit v1.2.3