mirror of https://github.com/mpv-player/mpv
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:
parent
f30c2c99d1
commit
dc582f2505
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue