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.
This commit is contained in:
wm4 2013-12-01 23:39:13 +01:00
parent f30c2c99d1
commit dc582f2505
6 changed files with 91 additions and 44 deletions

View File

@ -486,6 +486,11 @@ Available video output drivers are:
Set the YUV chroma sample location. auto means use the bitstream
flags (default: auto).
``rectangle-textures``
Force use of rectangle textures (default: no). Normally this shouldn't
have any advantages over normal textures. Note that hardware decoding
overrides this flag.
``opengl-hq``
Same as ``opengl``, but with default settings for high quality rendering.

View File

@ -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 {

View File

@ -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" },

View File

@ -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;

View File

@ -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

View File

@ -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) {