vo_opengl: further GL API use separation

Move multiple GL-specific things from the renderer to other places like
vo_opengl.c, vo_opengl_cb.c, and ra_gl.c.

The vp_w/vp_h parameters to gl_video_resize() make no sense anymore, and
are implicitly part of struct fbodst.

Checking the main framebuffer depth is moved to vo_opengl.c. For
vo_opengl_cb.c it always assumes 8. The API user now has to override
this manually. The previous heuristic didn't make much sense anyway.

The only remaining dependency on GL is the hwdec stuff, which is harder
to change.
This commit is contained in:
wm4 2017-08-07 19:14:18 +02:00
parent 1adf324d8b
commit 47ea771b7a
15 changed files with 172 additions and 122 deletions

View File

@ -30,6 +30,11 @@ Interface changes
- --opengl-fbo-format changes from a choice to a string. Also, its value - --opengl-fbo-format changes from a choice to a string. Also, its value
will be checked only on renderer initialization, rather than when the will be checked only on renderer initialization, rather than when the
option is set. option is set.
- Using opengl-cb now always assumes 8 bit per component depth, and dithers
to this size. Before, it tried to figure out the depth of the first
framebuffer that was ever passed to the renderer. Having GL framebuffers
with a size larger than 8 bit per component is quite rare. If you need
it, set the --dither-depth option instead.
--- mpv 0.26.0 --- --- mpv 0.26.0 ---
- remove remaining deprecated audio device options, like --alsa-device - remove remaining deprecated audio device options, like --alsa-device
Some of them were removed in earlier releases. Some of them were removed in earlier releases.

View File

@ -115,6 +115,12 @@ bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2)
return rc->x1 > rc->x0 && rc->y1 > rc->y0; return rc->x1 > rc->x0 && rc->y1 > rc->y0;
} }
bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2)
{
return rc1->x0 == rc2->x0 && rc1->y0 == rc2->y0 &&
rc1->x1 == rc2->x1 && rc1->y1 == rc2->y1;
}
// This works like snprintf(), except that it starts writing the first output // This works like snprintf(), except that it starts writing the first output
// character to str[strlen(str)]. This returns the number of characters the // character to str[strlen(str)]. This returns the number of characters the
// string would have *appended* assuming a large enough buffer, will make sure // string would have *appended* assuming a large enough buffer, will make sure

View File

@ -82,6 +82,7 @@ struct mp_rect {
void mp_rect_union(struct mp_rect *rc, const struct mp_rect *src); void mp_rect_union(struct mp_rect *rc, const struct mp_rect *src);
bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2); bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2);
bool mp_rect_contains(struct mp_rect *rc, int x, int y); bool mp_rect_contains(struct mp_rect *rc, int x, int y);
bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2);
int mp_snprintf_cat(char *str, size_t size, const char *format, ...) int mp_snprintf_cat(char *str, size_t size, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4); PRINTF_ATTRIBUTE(3, 4);

View File

@ -625,10 +625,8 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
} }
// GL_ARB_compute_shader & GL_ARB_shader_image_load_store // GL_ARB_compute_shader & GL_ARB_shader_image_load_store
if (gl->DispatchCompute && gl->BindImageTexture) { if (gl->DispatchCompute && gl->BindImageTexture)
gl->mpgl_caps |= MPGL_CAP_COMPUTE_SHADER; gl->mpgl_caps |= MPGL_CAP_COMPUTE_SHADER;
gl->GetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &gl->max_shmem);
}
// Provided for simpler handling if no framebuffer support is available. // Provided for simpler handling if no framebuffer support is available.
if (!gl->BindFramebuffer) if (!gl->BindFramebuffer)

View File

@ -87,7 +87,6 @@ struct GL {
int glsl_version; // e.g. 130 for GLSL 1.30 int glsl_version; // e.g. 130 for GLSL 1.30
char *extensions; // Equivalent to GL_EXTENSIONS char *extensions; // Equivalent to GL_EXTENSIONS
int mpgl_caps; // Bitfield of MPGL_CAP_* constants int mpgl_caps; // Bitfield of MPGL_CAP_* constants
int max_shmem; // Maximum shared memory for compute shaders
bool debug_context; // use of e.g. GLX_CONTEXT_DEBUG_BIT_ARB bool debug_context; // use of e.g. GLX_CONTEXT_DEBUG_BIT_ARB
// Use mpgl_get_native_display() instead. Also, this is set to use the // Use mpgl_get_native_display() instead. Also, this is set to use the

View File

@ -76,7 +76,7 @@ struct gl_hwdec_driver {
int (*overlay_frame)(struct gl_hwdec *hw, struct mp_image *hw_image); int (*overlay_frame)(struct gl_hwdec *hw, struct mp_image *hw_image);
// Move overlay position within the "window". // Move overlay position within the "window".
void (*overlay_adjust)(struct gl_hwdec *hw, int w, int h, void (*overlay_adjust)(struct gl_hwdec *hw,
struct mp_rect *src, struct mp_rect *dst); struct mp_rect *src, struct mp_rect *dst);
}; };

View File

@ -50,7 +50,6 @@ struct priv {
struct mp_image *current_frame; struct mp_image *current_frame;
int w, h;
struct mp_rect src, dst; struct mp_rect src, dst;
int cur_window[4]; // raw user params int cur_window[4]; // raw user params
}; };
@ -131,9 +130,6 @@ static void update_overlay(struct gl_hwdec *hw, bool check_window_only)
struct mp_rect src = p->src; struct mp_rect src = p->src;
struct mp_rect dst = p->dst; struct mp_rect dst = p->dst;
if (!p->w || !p->h)
return;
int defs[4] = {0, 0, 0, 0}; int defs[4] = {0, 0, 0, 0};
int *z = mpgl_get_native_display(gl, "MPV_RPI_WINDOW"); int *z = mpgl_get_native_display(gl, "MPV_RPI_WINDOW");
if (!z) if (!z)
@ -248,13 +244,11 @@ static int enable_renderer(struct gl_hwdec *hw)
return 0; return 0;
} }
static void overlay_adjust(struct gl_hwdec *hw, int w, int h, static void overlay_adjust(struct gl_hwdec *hw,
struct mp_rect *src, struct mp_rect *dst) struct mp_rect *src, struct mp_rect *dst)
{ {
struct priv *p = hw->priv; struct priv *p = hw->priv;
p->w = w;
p->h = h;
p->src = *src; p->src = *src;
p->dst = *dst; p->dst = *dst;

View File

@ -28,6 +28,14 @@ void ra_buf_free(struct ra *ra, struct ra_buf **buf)
*buf = NULL; *buf = NULL;
} }
void ra_free(struct ra **ra)
{
if (*ra)
(*ra)->fns->destroy(*ra);
talloc_free(*ra);
*ra = NULL;
}
static size_t vartype_size(enum ra_vartype type) static size_t vartype_size(enum ra_vartype type)
{ {
switch (type) { switch (type) {

View File

@ -21,6 +21,10 @@ struct ra {
// at init time. // at init time.
int max_texture_wh; int max_texture_wh;
// Maximum shared memory for compute shaders. Set by the RA backend at init
// time.
size_t max_shmem;
// Set of supported texture formats. Must be added by RA backend at init time. // Set of supported texture formats. Must be added by RA backend at init time.
struct ra_format **formats; struct ra_format **formats;
int num_formats; int num_formats;
@ -391,6 +395,12 @@ struct ra_fns {
// always produce a value - and the values it does produce are typically // always produce a value - and the values it does produce are typically
// delayed by a few frames. When no value is available, this returns 0. // delayed by a few frames. When no value is available, this returns 0.
uint64_t (*timer_stop)(struct ra *ra, ra_timer *timer); uint64_t (*timer_stop)(struct ra *ra, ra_timer *timer);
// Hint that possibly queued up commands should be sent to the GPU. Optional.
void (*flush)(struct ra *ra);
// Optional.
void (*debug_marker)(struct ra *ra, const char *msg);
}; };
struct ra_tex *ra_tex_create(struct ra *ra, const struct ra_tex_params *params); struct ra_tex *ra_tex_create(struct ra *ra, const struct ra_tex_params *params);
@ -399,6 +409,8 @@ void ra_tex_free(struct ra *ra, struct ra_tex **tex);
struct ra_buf *ra_buf_create(struct ra *ra, const struct ra_buf_params *params); struct ra_buf *ra_buf_create(struct ra *ra, const struct ra_buf_params *params);
void ra_buf_free(struct ra *ra, struct ra_buf **buf); void ra_buf_free(struct ra *ra, struct ra_buf **buf);
void ra_free(struct ra **ra);
const struct ra_format *ra_find_unorm_format(struct ra *ra, const struct ra_format *ra_find_unorm_format(struct ra *ra,
int bytes_per_component, int bytes_per_component,
int n_components); int n_components);

View File

@ -6,7 +6,7 @@
static struct ra_fns ra_fns_gl; static struct ra_fns ra_fns_gl;
int ra_init_gl(struct ra *ra, GL *gl) static int ra_init_gl(struct ra *ra, GL *gl)
{ {
if (gl->version < 210 && gl->es < 200) { if (gl->version < 210 && gl->es < 200) {
MP_ERR(ra, "At least OpenGL 2.1 or OpenGL ES 2.0 required.\n"); MP_ERR(ra, "At least OpenGL 2.1 or OpenGL ES 2.0 required.\n");
@ -16,6 +16,8 @@ int ra_init_gl(struct ra *ra, GL *gl)
struct ra_gl *p = ra->priv = talloc_zero(NULL, struct ra_gl); struct ra_gl *p = ra->priv = talloc_zero(NULL, struct ra_gl);
p->gl = gl; p->gl = gl;
ra_gl_set_debug(ra, true);
ra->fns = &ra_fns_gl; ra->fns = &ra_fns_gl;
ra->caps = 0; ra->caps = 0;
if (gl->mpgl_caps & MPGL_CAP_1D_TEX) if (gl->mpgl_caps & MPGL_CAP_1D_TEX)
@ -100,20 +102,46 @@ int ra_init_gl(struct ra *ra, GL *gl)
MP_TARRAY_APPEND(ra, ra->formats, ra->num_formats, fmt); MP_TARRAY_APPEND(ra, ra->formats, ra->num_formats, fmt);
} }
GLint max_wh; GLint ival;
gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_wh); gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &ival);
ra->max_texture_wh = max_wh; ra->max_texture_wh = ival;
if (ra->caps & RA_CAP_COMPUTE) {
gl->GetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &ival);
ra->max_shmem = ival;
}
gl->Disable(GL_DITHER); gl->Disable(GL_DITHER);
return 0; return 0;
} }
struct ra *ra_create_gl(GL *gl, struct mp_log *log)
{
struct ra *ra = talloc_zero(NULL, struct ra);
ra->log = log;
if (ra_init_gl(ra, gl) < 0) {
talloc_free(ra);
return NULL;
}
return ra;
}
static void gl_destroy(struct ra *ra) static void gl_destroy(struct ra *ra)
{ {
talloc_free(ra->priv); talloc_free(ra->priv);
} }
void ra_gl_set_debug(struct ra *ra, bool enable)
{
struct ra_gl *p = ra->priv;
GL *gl = ra_gl_get(ra);
p->debug_enable = enable;
if (gl->debug_context)
gl_set_debug_logger(gl, enable ? ra->log : NULL);
}
static void gl_tex_destroy(struct ra *ra, struct ra_tex *tex) static void gl_tex_destroy(struct ra *ra, struct ra_tex *tex)
{ {
GL *gl = ra_gl_get(ra); GL *gl = ra_gl_get(ra);
@ -949,6 +977,20 @@ static uint64_t gl_timer_stop(struct ra *ra, ra_timer *ratimer)
return timer->result; return timer->result;
} }
static void gl_flush(struct ra *ra)
{
GL *gl = ra_gl_get(ra);
gl->Flush();
}
static void gl_debug_marker(struct ra *ra, const char *msg)
{
struct ra_gl *p = ra->priv;
if (p->debug_enable)
gl_check_error(p->gl, ra->log, msg);
}
static struct ra_fns ra_fns_gl = { static struct ra_fns ra_fns_gl = {
.destroy = gl_destroy, .destroy = gl_destroy,
.tex_create = gl_tex_create, .tex_create = gl_tex_create,
@ -966,4 +1008,6 @@ static struct ra_fns ra_fns_gl = {
.timer_destroy = gl_timer_destroy, .timer_destroy = gl_timer_destroy,
.timer_start = gl_timer_start, .timer_start = gl_timer_start,
.timer_stop = gl_timer_stop, .timer_stop = gl_timer_stop,
.flush = gl_flush,
.debug_marker = gl_debug_marker,
}; };

View File

@ -7,6 +7,7 @@
// For ra.priv // For ra.priv
struct ra_gl { struct ra_gl {
GL *gl; GL *gl;
bool debug_enable;
}; };
// For ra_tex.priv // For ra_tex.priv
@ -37,11 +38,11 @@ struct ra_renderpass_gl {
struct gl_vao vao; struct gl_vao vao;
}; };
int ra_init_gl(struct ra *ra, GL *gl); struct ra *ra_create_gl(GL *gl, struct mp_log *log);
struct ra_tex *ra_create_wrapped_texture(struct ra *ra, GLuint gl_texture, struct ra_tex *ra_create_wrapped_texture(struct ra *ra, GLuint gl_texture,
GLenum gl_target, GLint gl_iformat, GLenum gl_target, GLint gl_iformat,
GLenum gl_format, GLenum gl_type, GLenum gl_format, GLenum gl_type,
int w, int h); int w, int h);
struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h); struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h);
GL *ra_gl_get(struct ra *ra); GL *ra_gl_get(struct ra *ra);
void ra_gl_set_debug(struct ra *ra, bool enable);

View File

@ -176,7 +176,6 @@ struct dr_buffer {
}; };
struct gl_video { struct gl_video {
GL *gl;
struct ra *ra; struct ra *ra;
struct mpv_global *global; struct mpv_global *global;
@ -184,7 +183,6 @@ struct gl_video {
struct gl_video_opts opts; struct gl_video_opts opts;
struct m_config_cache *opts_cache; struct m_config_cache *opts_cache;
struct gl_lcms *cms; struct gl_lcms *cms;
bool gl_debug;
int fb_depth; // actual bits available in GL main framebuffer int fb_depth; // actual bits available in GL main framebuffer
@ -252,7 +250,6 @@ struct gl_video {
struct mp_rect src_rect; // displayed part of the source video struct mp_rect src_rect; // displayed part of the source video
struct mp_rect dst_rect; // video rectangle on output window struct mp_rect dst_rect; // video rectangle on output window
struct mp_osd_res osd_rect; // OSD size/margins struct mp_osd_res osd_rect; // OSD size/margins
int vp_w, vp_h;
// temporary during rendering // temporary during rendering
struct img_tex pass_tex[TEXUNIT_VIDEO_NUM]; struct img_tex pass_tex[TEXUNIT_VIDEO_NUM];
@ -459,17 +456,8 @@ static struct bstr load_cached_file(struct gl_video *p, const char *path)
static void debug_check_gl(struct gl_video *p, const char *msg) static void debug_check_gl(struct gl_video *p, const char *msg)
{ {
if (p->gl_debug) if (p->ra->fns->debug_marker)
gl_check_error(p->gl, p->log, msg); p->ra->fns->debug_marker(p->ra, msg);
}
void gl_video_set_debug(struct gl_video *p, bool enable)
{
GL *gl = p->gl;
p->gl_debug = enable;
if (p->gl->debug_context)
gl_set_debug_logger(gl, enable ? p->log : NULL);
} }
static void gl_video_reset_surfaces(struct gl_video *p) static void gl_video_reset_surfaces(struct gl_video *p)
@ -1094,8 +1082,8 @@ static void pass_prepare_src_tex(struct gl_video *p)
gl_sc_uniform_vec2(sc, texture_size, f); gl_sc_uniform_vec2(sc, texture_size, f);
gl_sc_uniform_mat2(sc, texture_rot, true, (float *)s->transform.m); gl_sc_uniform_mat2(sc, texture_rot, true, (float *)s->transform.m);
gl_sc_uniform_vec2(sc, texture_off, (float *)s->transform.t); gl_sc_uniform_vec2(sc, texture_off, (float *)s->transform.t);
gl_sc_uniform_vec2(sc, pixel_size, (GLfloat[]){1.0f / f[0], gl_sc_uniform_vec2(sc, pixel_size, (float[]){1.0f / f[0],
1.0f / f[1]}); 1.0f / f[1]});
} }
} }
@ -1137,7 +1125,7 @@ static void dispatch_compute(struct gl_video *p, int w, int h,
// We need to rescale the coordinates to the true texture size // We need to rescale the coordinates to the true texture size
char tex_scale[32]; char tex_scale[32];
snprintf(tex_scale, sizeof(tex_scale), "tex_scale%d", n); snprintf(tex_scale, sizeof(tex_scale), "tex_scale%d", n);
gl_sc_uniform_vec2(p->sc, tex_scale, (GLfloat[2]){ gl_sc_uniform_vec2(p->sc, tex_scale, (float[2]){
(float)s->w / s->tex->params.w, (float)s->w / s->tex->params.w,
(float)s->h / s->tex->params.h, (float)s->h / s->tex->params.h,
}); });
@ -1514,18 +1502,18 @@ static void load_shader(struct gl_video *p, struct bstr body)
gl_sc_uniform_f(p->sc, "random", (double)av_lfg_get(&p->lfg) / UINT32_MAX); gl_sc_uniform_f(p->sc, "random", (double)av_lfg_get(&p->lfg) / UINT32_MAX);
gl_sc_uniform_i(p->sc, "frame", p->frames_uploaded); gl_sc_uniform_i(p->sc, "frame", p->frames_uploaded);
gl_sc_uniform_vec2(p->sc, "input_size", gl_sc_uniform_vec2(p->sc, "input_size",
(GLfloat[]){(p->src_rect.x1 - p->src_rect.x0) * (float[]){(p->src_rect.x1 - p->src_rect.x0) *
p->texture_offset.m[0][0], p->texture_offset.m[0][0],
(p->src_rect.y1 - p->src_rect.y0) * (p->src_rect.y1 - p->src_rect.y0) *
p->texture_offset.m[1][1]}); p->texture_offset.m[1][1]});
gl_sc_uniform_vec2(p->sc, "target_size", gl_sc_uniform_vec2(p->sc, "target_size",
(GLfloat[]){p->dst_rect.x1 - p->dst_rect.x0, (float[]){p->dst_rect.x1 - p->dst_rect.x0,
p->dst_rect.y1 - p->dst_rect.y0}); p->dst_rect.y1 - p->dst_rect.y0});
gl_sc_uniform_vec2(p->sc, "tex_offset", gl_sc_uniform_vec2(p->sc, "tex_offset",
(GLfloat[]){p->src_rect.x0 * p->texture_offset.m[0][0] + (float[]){p->src_rect.x0 * p->texture_offset.m[0][0] +
p->texture_offset.t[0], p->texture_offset.t[0],
p->src_rect.y0 * p->texture_offset.m[1][1] + p->src_rect.y0 * p->texture_offset.m[1][1] +
p->texture_offset.t[1]}); p->texture_offset.t[1]});
} }
// Semantic equality // Semantic equality
@ -1688,8 +1676,6 @@ static void pass_sample_separated(struct gl_video *p, struct img_tex src,
static void pass_dispatch_sample_polar(struct gl_video *p, struct scaler *scaler, static void pass_dispatch_sample_polar(struct gl_video *p, struct scaler *scaler,
struct img_tex tex, int w, int h) struct img_tex tex, int w, int h)
{ {
GL *gl = p->gl;
uint64_t reqs = RA_CAP_COMPUTE | RA_CAP_NESTED_ARRAY; uint64_t reqs = RA_CAP_COMPUTE | RA_CAP_NESTED_ARRAY;
if ((p->ra->caps & reqs) != reqs) if ((p->ra->caps & reqs) != reqs)
goto fallback; goto fallback;
@ -1713,8 +1699,8 @@ static void pass_dispatch_sample_polar(struct gl_video *p, struct scaler *scaler
int iw = (int)ceil(bw / ratiox) + padding + 1, int iw = (int)ceil(bw / ratiox) + padding + 1,
ih = (int)ceil(bh / ratioy) + padding + 1; ih = (int)ceil(bh / ratioy) + padding + 1;
int shmem_req = iw * ih * tex.components * sizeof(GLfloat); int shmem_req = iw * ih * tex.components * sizeof(float);
if (shmem_req > gl->max_shmem) if (shmem_req > p->ra->max_shmem)
goto fallback; goto fallback;
pass_is_compute(p, bw, bh); pass_is_compute(p, bw, bh);
@ -2499,10 +2485,15 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool
} }
} }
void gl_video_set_fb_depth(struct gl_video *p, int fb_depth)
{
p->fb_depth = fb_depth;
}
static void pass_dither(struct gl_video *p) static void pass_dither(struct gl_video *p)
{ {
// Assume 8 bits per component if unknown. // Assume 8 bits per component if unknown.
int dst_depth = p->fb_depth; int dst_depth = p->fb_depth > 0 ? p->fb_depth : 8;
if (p->opts.dither_depth > 0) if (p->opts.dither_depth > 0)
dst_depth = p->opts.dither_depth; dst_depth = p->opts.dither_depth;
@ -3001,40 +2992,16 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
p->frames_drawn += 1; p->frames_drawn += 1;
} }
// (fbo==0 makes BindFramebuffer select the screen backbuffer) void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo) struct fbodst target)
{ {
GL *gl = p->gl; struct mp_rect target_rc = {0, 0, target.tex->params.w, target.tex->params.h};
if (fbo && !(gl->mpgl_caps & MPGL_CAP_FB)) {
MP_FATAL(p, "Rendering to FBO requested, but no FBO extension found!\n");
return;
}
if (p->fb_depth == 0) {
debug_check_gl(p, "before retrieving framebuffer depth");
p->fb_depth = gl_get_fb_depth(gl, fbo);
debug_check_gl(p, "retrieving framebuffer depth");
if (p->fb_depth > 0) {
MP_VERBOSE(p, "Reported display depth: %d\n", p->fb_depth);
} else {
p->fb_depth = 8;
}
}
struct fbodst target = {
.tex = ra_create_wrapped_fb(p->ra, fbo, p->vp_w, abs(p->vp_h)),
.flip = p->vp_h < 0,
};
struct mp_rect target_rc = {0, 0, p->vp_w, abs(p->vp_h)};
p->broken_frame = false; p->broken_frame = false;
bool has_frame = !!frame->current; bool has_frame = !!frame->current;
if (!has_frame || p->dst_rect.x0 > 0 || p->dst_rect.y0 > 0 || if (!has_frame || !mp_rect_equals(&p->dst_rect, &target_rc)) {
p->dst_rect.x1 < p->vp_w || p->dst_rect.y1 < abs(p->vp_h))
{
struct m_color c = p->opts.background; struct m_color c = p->opts.background;
float color[4] = {c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0}; float color[4] = {c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0};
p->ra->fns->clear(p->ra, target.tex, color, &target_rc); p->ra->fns->clear(p->ra, target.tex, color, &target_rc);
@ -3140,32 +3107,27 @@ done:
p->ra->fns->clear(p->ra, target.tex, color, &target_rc); p->ra->fns->clear(p->ra, target.tex, color, &target_rc);
} }
ra_tex_free(p->ra, &target.tex);
// The playloop calls this last before waiting some time until it decides // The playloop calls this last before waiting some time until it decides
// to call flip_page(). Tell OpenGL to start execution of the GPU commands // to call flip_page(). Tell OpenGL to start execution of the GPU commands
// while we sleep (this happens asynchronously). // while we sleep (this happens asynchronously).
if ((p->opts.early_flush == -1 && !frame->display_synced) || if ((p->opts.early_flush == -1 && !frame->display_synced) ||
p->opts.early_flush == 1) p->opts.early_flush == 1)
{ {
gl->Flush(); if (p->ra->fns->flush)
p->ra->fns->flush(p->ra);
} }
p->frames_rendered++; p->frames_rendered++;
pass_report_performance(p); pass_report_performance(p);
} }
// vp_w/vp_h is the implicit size of the target framebuffer. void gl_video_resize(struct gl_video *p,
// vp_h can be negative to flip the screen.
void gl_video_resize(struct gl_video *p, int vp_w, int vp_h,
struct mp_rect *src, struct mp_rect *dst, struct mp_rect *src, struct mp_rect *dst,
struct mp_osd_res *osd) struct mp_osd_res *osd)
{ {
p->src_rect = *src; p->src_rect = *src;
p->dst_rect = *dst; p->dst_rect = *dst;
p->osd_rect = *osd; p->osd_rect = *osd;
p->vp_w = vp_w;
p->vp_h = vp_h;
gl_video_reset_surfaces(p); gl_video_reset_surfaces(p);
@ -3173,7 +3135,7 @@ void gl_video_resize(struct gl_video *p, int vp_w, int vp_h,
mpgl_osd_resize(p->osd, p->osd_rect, p->image_params.stereo_out); mpgl_osd_resize(p->osd, p->osd_rect, p->image_params.stereo_out);
if (p->hwdec && p->hwdec->driver->overlay_adjust) if (p->hwdec && p->hwdec->driver->overlay_adjust)
p->hwdec->driver->overlay_adjust(p->hwdec, vp_w, abs(vp_h), src, dst); p->hwdec->driver->overlay_adjust(p->hwdec, src, dst);
} }
static void frame_perf_data(struct pass_info pass[], struct mp_frame_perf *out) static void frame_perf_data(struct pass_info pass[], struct mp_frame_perf *out)
@ -3375,10 +3337,10 @@ static bool check_dumb_mode(struct gl_video *p)
static void check_gl_features(struct gl_video *p) static void check_gl_features(struct gl_video *p)
{ {
struct ra *ra = p->ra; struct ra *ra = p->ra;
GL *gl = p->gl;
bool have_float_tex = !!ra_find_float16_format(ra, 1); bool have_float_tex = !!ra_find_float16_format(ra, 1);
bool have_mglsl = ra->glsl_version >= 130; // modern GLSL bool have_mglsl = ra->glsl_version >= 130; // modern GLSL
bool have_texrg = gl->mpgl_caps & MPGL_CAP_TEX_RG; const struct ra_format *rg_tex = ra_find_unorm_format(p->ra, 1, 2);
bool have_texrg = rg_tex && !rg_tex->luminance_alpha;
bool have_compute = ra->caps & RA_CAP_COMPUTE; bool have_compute = ra->caps & RA_CAP_COMPUTE;
bool have_ssbo = ra->caps & RA_CAP_BUF_RW; bool have_ssbo = ra->caps & RA_CAP_BUF_RW;
@ -3512,8 +3474,6 @@ void gl_video_uninit(struct gl_video *p)
if (!p) if (!p)
return; return;
GL *gl = p->gl;
uninit_video(p); uninit_video(p);
gl_sc_destroy(p->sc); gl_sc_destroy(p->sc);
@ -3532,8 +3492,6 @@ void gl_video_uninit(struct gl_video *p)
mpgl_osd_destroy(p->osd); mpgl_osd_destroy(p->osd);
gl_set_debug_logger(gl, NULL);
// Forcibly destroy possibly remaining image references. This should also // Forcibly destroy possibly remaining image references. This should also
// cause gl_video_dr_free_buffer() to be called for the remaining buffers. // cause gl_video_dr_free_buffer() to be called for the remaining buffers.
gc_pending_dr_fences(p, true); gc_pending_dr_fences(p, true);
@ -3541,8 +3499,7 @@ void gl_video_uninit(struct gl_video *p)
// Should all have been unreffed already. // Should all have been unreffed already.
assert(!p->num_dr_buffers); assert(!p->num_dr_buffers);
p->ra->fns->destroy(p->ra); ra_free(&p->ra);
talloc_free(p->ra);
talloc_free(p); talloc_free(p);
} }
@ -3603,18 +3560,11 @@ void gl_video_set_osd_source(struct gl_video *p, struct osd_state *osd)
reinit_osd(p); reinit_osd(p);
} }
struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g) struct gl_video *gl_video_init(struct ra *ra, struct mp_log *log,
struct mpv_global *g)
{ {
struct ra *ra = talloc_zero(NULL, struct ra);
ra->log = log;
if (ra_init_gl(ra, gl) < 0) {
talloc_free(ra);
return NULL;
}
struct gl_video *p = talloc_ptrtype(NULL, p); struct gl_video *p = talloc_ptrtype(NULL, p);
*p = (struct gl_video) { *p = (struct gl_video) {
.gl = gl,
.ra = ra, .ra = ra,
.global = g, .global = g,
.log = log, .log = log,
@ -3628,7 +3578,6 @@ struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g)
p->opts = *opts; p->opts = *opts;
for (int n = 0; n < SCALER_COUNT; n++) for (int n = 0; n < SCALER_COUNT; n++)
p->scaler[n] = (struct scaler){.index = n}; p->scaler[n] = (struct scaler){.index = n};
gl_video_set_debug(p, true);
init_gl(p); init_gl(p);
reinit_from_options(p); reinit_from_options(p);
return p; return p;

View File

@ -24,7 +24,6 @@
#include "sub/osd.h" #include "sub/osd.h"
#include "common.h" #include "common.h"
#include "utils.h" #include "utils.h"
#include "gl_utils.h"
#include "lcms.h" #include "lcms.h"
#include "shader_cache.h" #include "shader_cache.h"
#include "video/out/filter_kernels.h" #include "video/out/filter_kernels.h"
@ -150,24 +149,25 @@ extern const struct m_sub_options gl_video_conf;
struct gl_video; struct gl_video;
struct vo_frame; struct vo_frame;
struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g); struct gl_video *gl_video_init(struct ra *ra, struct mp_log *log,
struct mpv_global *g);
void gl_video_uninit(struct gl_video *p); void gl_video_uninit(struct gl_video *p);
void gl_video_set_osd_source(struct gl_video *p, struct osd_state *osd); void gl_video_set_osd_source(struct gl_video *p, struct osd_state *osd);
void gl_video_update_options(struct gl_video *p); void gl_video_update_options(struct gl_video *p);
bool gl_video_check_format(struct gl_video *p, int mp_format); bool gl_video_check_format(struct gl_video *p, int mp_format);
void gl_video_config(struct gl_video *p, struct mp_image_params *params); void gl_video_config(struct gl_video *p, struct mp_image_params *params);
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b); void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo); void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
void gl_video_resize(struct gl_video *p, int vp_w, int vp_h, struct fbodst target);
void gl_video_resize(struct gl_video *p,
struct mp_rect *src, struct mp_rect *dst, struct mp_rect *src, struct mp_rect *dst,
struct mp_osd_res *osd); struct mp_osd_res *osd);
void gl_video_set_fb_depth(struct gl_video *p, int fb_depth);
void gl_video_perfdata(struct gl_video *p, struct voctrl_performance_data *out); void gl_video_perfdata(struct gl_video *p, struct voctrl_performance_data *out);
struct mp_csp_equalizer; struct mp_csp_equalizer;
struct mp_csp_equalizer *gl_video_eq_ptr(struct gl_video *p); struct mp_csp_equalizer *gl_video_eq_ptr(struct gl_video *p);
void gl_video_eq_update(struct gl_video *p); void gl_video_eq_update(struct gl_video *p);
void gl_video_set_debug(struct gl_video *p, bool enable);
float gl_video_scale_ambient_lux(float lmin, float lmax, float gl_video_scale_ambient_lux(float lmin, float lmax,
float rmin, float rmax, float lux); float rmin, float rmax, float lux);
void gl_video_set_ambient_lux(struct gl_video *p, int lux); void gl_video_set_ambient_lux(struct gl_video *p, int lux);

View File

@ -45,6 +45,7 @@
#include "filter_kernels.h" #include "filter_kernels.h"
#include "video/hwdec.h" #include "video/hwdec.h"
#include "opengl/video.h" #include "opengl/video.h"
#include "opengl/ra_gl.h"
#define NUM_VSYNC_FENCES 10 #define NUM_VSYNC_FENCES 10
@ -65,6 +66,7 @@ struct gl_priv {
struct mp_log *log; struct mp_log *log;
MPGLContext *glctx; MPGLContext *glctx;
GL *gl; GL *gl;
struct ra *ra;
struct vo_opengl_opts opts; struct vo_opengl_opts opts;
@ -95,8 +97,7 @@ static void resize(struct gl_priv *p)
struct mp_osd_res osd; struct mp_osd_res osd;
vo_get_src_dst_rects(vo, &src, &dst, &osd); vo_get_src_dst_rects(vo, &src, &dst, &osd);
int height = p->glctx->flip_v ? vo->dheight : -vo->dheight; gl_video_resize(p->renderer, &src, &dst, &osd);
gl_video_resize(p->renderer, vo->dwidth, height, &src, &dst, &osd);
vo->want_redraw = true; vo->want_redraw = true;
} }
@ -130,7 +131,13 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
p->vsync_fences[p->num_vsync_fences++] = fence; p->vsync_fences[p->num_vsync_fences++] = fence;
} }
gl_video_render_frame(p->renderer, frame, p->glctx->main_fb); struct fbodst target = {
.tex = ra_create_wrapped_fb(p->ra, p->glctx->main_fb,
vo->dwidth, vo->dheight),
.flip = !p->glctx->flip_v,
};
gl_video_render_frame(p->renderer, frame, target);
ra_tex_free(p->ra, &target.tex);
if (p->opts.use_glFinish) if (p->opts.use_glFinish)
gl->Finish(); gl->Finish();
@ -145,7 +152,7 @@ static void flip_page(struct vo *vo)
p->frames_rendered++; p->frames_rendered++;
if (p->frames_rendered > 5 && !p->opts.use_gl_debug) if (p->frames_rendered > 5 && !p->opts.use_gl_debug)
gl_video_set_debug(p->renderer, false); ra_gl_set_debug(p->ra, false);
if (p->opts.use_glFinish) if (p->opts.use_glFinish)
gl->Finish(); gl->Finish();
@ -422,9 +429,11 @@ static int preinit(struct vo *vo)
MP_VERBOSE(vo, "swap_control extension missing.\n"); MP_VERBOSE(vo, "swap_control extension missing.\n");
} }
p->renderer = gl_video_init(p->gl, vo->log, vo->global); p->ra = ra_create_gl(p->gl, vo->log);
if (!p->renderer) if (!p->ra)
goto err_out; goto err_out;
p->renderer = gl_video_init(p->ra, vo->log, vo->global);
gl_video_set_osd_source(p->renderer, vo->osd); gl_video_set_osd_source(p->renderer, vo->osd);
gl_video_configure_queue(p->renderer, vo); gl_video_configure_queue(p->renderer, vo);
@ -438,6 +447,13 @@ static int preinit(struct vo *vo)
vo->hwdec_devs, vo->opts->gl_hwdec_interop); vo->hwdec_devs, vo->opts->gl_hwdec_interop);
gl_video_set_hwdec(p->renderer, p->hwdec); gl_video_set_hwdec(p->renderer, p->hwdec);
gl_check_error(p->gl, p->log, "before retrieving framebuffer depth");
int fb_depth = gl_get_fb_depth(p->gl, p->glctx->main_fb);
gl_check_error(p->gl, p->log, "retrieving framebuffer depth");
if (fb_depth)
MP_VERBOSE(p, "Reported display depth: %d\n", fb_depth);
gl_video_set_fb_depth(p->renderer, fb_depth);
return 0; return 0;
err_out: err_out:

View File

@ -27,6 +27,7 @@
#include "opengl/common.h" #include "opengl/common.h"
#include "opengl/video.h" #include "opengl/video.h"
#include "opengl/hwdec.h" #include "opengl/hwdec.h"
#include "opengl/ra_gl.h"
#include "libmpv/opengl_cb.h" #include "libmpv/opengl_cb.h"
@ -87,6 +88,7 @@ struct mpv_opengl_cb_context {
// application's OpenGL context is current - i.e. only while the // application's OpenGL context is current - i.e. only while the
// host application is calling certain mpv_opengl_cb_* APIs. // host application is calling certain mpv_opengl_cb_* APIs.
GL *gl; GL *gl;
struct ra *ra;
struct gl_video *renderer; struct gl_video *renderer;
struct gl_hwdec *hwdec; struct gl_hwdec *hwdec;
struct m_config_cache *vo_opts_cache; struct m_config_cache *vo_opts_cache;
@ -171,10 +173,12 @@ int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts,
return MPV_ERROR_UNSUPPORTED; return MPV_ERROR_UNSUPPORTED;
} }
ctx->renderer = gl_video_init(ctx->gl, ctx->log, ctx->global); ctx->ra = ra_create_gl(ctx->gl, ctx->log);
if (!ctx->renderer) if (!ctx->ra)
return MPV_ERROR_UNSUPPORTED; return MPV_ERROR_UNSUPPORTED;
ctx->renderer = gl_video_init(ctx->ra, ctx->log, ctx->global);
m_config_cache_update(ctx->vo_opts_cache); m_config_cache_update(ctx->vo_opts_cache);
ctx->hwdec_devs = hwdec_devices_create(); ctx->hwdec_devs = hwdec_devices_create();
@ -223,6 +227,7 @@ int mpv_opengl_cb_uninit_gl(struct mpv_opengl_cb_context *ctx)
ctx->hwdec = NULL; ctx->hwdec = NULL;
hwdec_devices_destroy(ctx->hwdec_devs); hwdec_devices_destroy(ctx->hwdec_devs);
ctx->hwdec_devs = NULL; ctx->hwdec_devs = NULL;
ra_free(&ctx->ra);
talloc_free(ctx->gl); talloc_free(ctx->gl);
ctx->gl = NULL; ctx->gl = NULL;
return 0; return 0;
@ -232,6 +237,16 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
{ {
assert(ctx->renderer); assert(ctx->renderer);
if (fbo && !(ctx->gl->mpgl_caps & MPGL_CAP_FB)) {
MP_FATAL(ctx, "Rendering to FBO requested, but no FBO extension found!\n");
return MPV_ERROR_UNSUPPORTED;
}
struct fbodst target = {
.tex = ra_create_wrapped_fb(ctx->ra, fbo, vp_w, abs(vp_h)),
.flip = vp_h < 0,
};
reset_gl_state(ctx->gl); reset_gl_state(ctx->gl);
pthread_mutex_lock(&ctx->lock); pthread_mutex_lock(&ctx->lock);
@ -256,7 +271,7 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
&ctx->img_params, vp_w, abs(vp_h), &ctx->img_params, vp_w, abs(vp_h),
1.0, &src, &dst, &osd); 1.0, &src, &dst, &osd);
gl_video_resize(ctx->renderer, vp_w, vp_h, &src, &dst, &osd); gl_video_resize(ctx->renderer, &src, &dst, &osd);
} }
if (ctx->reconfigured) { if (ctx->reconfigured) {
@ -272,7 +287,7 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
mp_read_option_raw(ctx->global, "opengl-debug", &m_option_type_flag, mp_read_option_raw(ctx->global, "opengl-debug", &m_option_type_flag,
&debug); &debug);
ctx->gl->debug_context = debug; ctx->gl->debug_context = debug;
gl_video_set_debug(ctx->renderer, debug); ra_gl_set_debug(ctx->ra, debug);
if (gl_video_icc_auto_enabled(ctx->renderer)) if (gl_video_icc_auto_enabled(ctx->renderer))
MP_ERR(ctx, "icc-profile-auto is not available with opengl-cb\n"); MP_ERR(ctx, "icc-profile-auto is not available with opengl-cb\n");
} }
@ -315,7 +330,7 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
pthread_mutex_unlock(&ctx->lock); pthread_mutex_unlock(&ctx->lock);
MP_STATS(ctx, "glcb-render"); MP_STATS(ctx, "glcb-render");
gl_video_render_frame(ctx->renderer, frame, fbo); gl_video_render_frame(ctx->renderer, frame, target);
reset_gl_state(ctx->gl); reset_gl_state(ctx->gl);
@ -327,6 +342,8 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
pthread_cond_wait(&ctx->wakeup, &ctx->lock); pthread_cond_wait(&ctx->wakeup, &ctx->lock);
pthread_mutex_unlock(&ctx->lock); pthread_mutex_unlock(&ctx->lock);
ra_tex_free(ctx->ra, &target.tex);
return 0; return 0;
} }